]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
grammar: split %union to group together related aspects
[bison.git] / src / muscle-tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
7d6bad19 3 Copyright (C) 2001-2013 Free Software Foundation, Inc.
f753cd62
MA
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
f16b0819 7 This program is free software: you can redistribute it and/or modify
f753cd62 8 it under the terms of the GNU General Public License as published by
f16b0819
PE
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
f753cd62 11
f16b0819 12 This program is distributed in the hope that it will be useful,
f753cd62
MA
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
f16b0819 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
f753cd62 19
2cec9080 20#include <config.h>
f753cd62 21#include "system.h"
8322e8f5
PE
22
23#include <hash.h>
8322e8f5 24
9611cfa2 25#include "complain.h"
f753cd62 26#include "files.h"
f508cb0a 27#include "getargs.h"
4a9cd8f2
AD
28#include "muscle-tab.h"
29#include "quote.h"
f753cd62 30
eb095650
PE
31/* A key-value pair, along with storage that can be reclaimed when
32 this pair is no longer needed. */
8322e8f5
PE
33typedef struct
34{
eb095650
PE
35 char const *key;
36 char const *value;
37 char *storage;
8322e8f5 38} muscle_entry;
592e8d4d
AD
39
40/* An obstack used to create some entries. */
41struct obstack muscle_obstack;
42
beda758b
AD
43/* Initial capacity of muscles hash table. */
44#define HT_INITIAL_CAPACITY 257
f753cd62 45
04098407 46static struct hash_table *muscle_table = NULL;
f753cd62 47
beda758b
AD
48static bool
49hash_compare_muscles (void const *x, void const *y)
f753cd62 50{
8322e8f5
PE
51 muscle_entry const *m1 = x;
52 muscle_entry const *m2 = y;
f518dbaf 53 return STREQ (m1->key, m2->key);
f753cd62
MA
54}
55
233a88ad
PE
56static size_t
57hash_muscle (const void *x, size_t tablesize)
f753cd62 58{
8322e8f5 59 muscle_entry const *m = x;
beda758b 60 return hash_string (m->key, tablesize);
f753cd62
MA
61}
62
c56d0037
AD
63/* Create a fresh muscle name KEY, and insert in the hash table. */
64static void *
65muscle_entry_new (char const *key)
66{
67 muscle_entry *res = xmalloc (sizeof *res);
68 res->key = key;
69 res->value = NULL;
70 res->storage = NULL;
71 if (!hash_insert (muscle_table, res))
72 xalloc_die ();
73 return res;
74}
75
eb095650
PE
76static void
77muscle_entry_free (void *entry)
78{
79 muscle_entry *mentry = entry;
80 free (mentry->storage);
81 free (mentry);
82}
83
f753cd62
MA
84void
85muscle_init (void)
86{
ae7453f2
AD
87 /* Initialize the muscle obstack. */
88 obstack_init (&muscle_obstack);
89
beda758b 90 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
e9690142 91 hash_compare_muscles, muscle_entry_free);
f753cd62
MA
92
93 /* Version and input file. */
ae7453f2 94 MUSCLE_INSERT_STRING ("version", VERSION);
f753cd62
MA
95}
96
592e8d4d 97
592e8d4d
AD
98void
99muscle_free (void)
100{
101 hash_free (muscle_table);
102 obstack_free (&muscle_obstack, NULL);
103}
104
c56d0037
AD
105/* Look for the muscle named KEY. Return NULL if does not exist. */
106static
107muscle_entry *
108muscle_lookup (char const *key)
f753cd62 109{
8322e8f5 110 muscle_entry probe;
ae7453f2 111 probe.key = key;
c56d0037
AD
112 return hash_lookup (muscle_table, &probe);
113}
beda758b 114
c56d0037
AD
115
116void
117muscle_insert (char const *key, char const *value)
118{
119 muscle_entry *entry = muscle_lookup (key);
120 if (entry)
4502eadc 121 free (entry->storage);
c56d0037
AD
122 else
123 /* First insertion in the hash. */
124 entry = muscle_entry_new (key);
beda758b 125 entry->value = value;
4502eadc 126 entry->storage = NULL;
f753cd62
MA
127}
128
ae7453f2
AD
129
130/*-------------------------------------------------------------------.
ff5150d9
PE
131| Append VALUE to the current value of KEY. If KEY did not already |
132| exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
133| associated value. Copy VALUE and SEPARATOR. |
ae7453f2
AD
134`-------------------------------------------------------------------*/
135
136void
137muscle_grow (const char *key, const char *val, const char *separator)
138{
c56d0037 139 muscle_entry *entry = muscle_lookup (key);
ae7453f2 140
c56d0037 141 if (entry)
ae7453f2
AD
142 {
143 /* Grow the current value. */
144 char *new_val;
6fbe73b6 145 obstack_printf (&muscle_obstack, "%s%s%s", entry->value, separator, val);
eb095650 146 free (entry->storage);
6fbe73b6 147 new_val = obstack_finish0 (&muscle_obstack);
eb095650 148 entry->value = entry->storage = xstrdup (new_val);
ae7453f2
AD
149 obstack_free (&muscle_obstack, new_val);
150 }
c56d0037
AD
151 else
152 {
153 /* First insertion in the hash. */
154 entry = muscle_entry_new (key);
155 entry->value = entry->storage = xstrdup (val);
156 }
ae7453f2
AD
157}
158
cd3684cf 159/*------------------------------------------------------------------.
35b8730d
JD
160| Using muscle_grow, append a synchronization line for the location |
161| LOC to the current value of KEY. |
cd3684cf
AD
162`------------------------------------------------------------------*/
163
35b8730d
JD
164static void
165muscle_syncline_grow (char const *key, location loc)
cd3684cf
AD
166{
167 char *extension = NULL;
aaf63e45 168 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
0601c3bf
AD
169 obstack_quote (&muscle_obstack,
170 quotearg_style (c_quoting_style, loc.start.file));
171 obstack_sgrow (&muscle_obstack, ")[");
6fbe73b6 172 extension = obstack_finish0 (&muscle_obstack);
cd3684cf 173 muscle_grow (key, extension, "");
eb095650 174 obstack_free (&muscle_obstack, extension);
cd3684cf
AD
175}
176
35b8730d
JD
177/*------------------------------------------------------------------.
178| Append VALUE to the current value of KEY, using muscle_grow. But |
179| in addition, issue a synchronization line for the location LOC |
180| using muscle_syncline_grow. |
181`------------------------------------------------------------------*/
182
183void
184muscle_code_grow (const char *key, const char *val, location loc)
185{
186 muscle_syncline_grow (key, loc);
187 muscle_grow (key, val, "\n");
188}
189
cd3684cf 190
c56d0037
AD
191void
192muscle_pair_list_grow (const char *muscle,
193 const char *a1, const char *a2)
ae7453f2 194{
66d30cd4 195 char *pair;
0601c3bf
AD
196 obstack_sgrow (&muscle_obstack, "[");
197 obstack_quote (&muscle_obstack, a1);
198 obstack_sgrow (&muscle_obstack, ", ");
199 obstack_quote (&muscle_obstack, a2);
200 obstack_sgrow (&muscle_obstack, "]");
6fbe73b6 201 pair = obstack_finish0 (&muscle_obstack);
66d30cd4
AD
202 muscle_grow (muscle, pair, ",\n");
203 obstack_free (&muscle_obstack, pair);
ae7453f2
AD
204}
205
7eb8a0bc 206
7eb8a0bc
JD
207char const *
208muscle_find_const (char const *key)
209{
c56d0037
AD
210 muscle_entry *entry = muscle_lookup (key);
211 return entry ? entry->value : NULL;
7eb8a0bc
JD
212}
213
214
ff5150d9 215char *
7eb8a0bc 216muscle_find (char const *key)
f753cd62 217{
c56d0037
AD
218 muscle_entry *entry = muscle_lookup (key);
219 if (entry)
4502eadc 220 {
c56d0037
AD
221 aver (entry->value == entry->storage);
222 return entry->storage;
4502eadc
JD
223 }
224 return NULL;
f753cd62 225}
be2a1a68
AD
226
227
45eebca4 228/* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
e5878229
AD
229 digraphs for special characters in the file name. */
230
231static void
9611cfa2
JD
232muscle_boundary_grow (char const *key, boundary bound)
233{
234 char *extension;
eea7239a 235 obstack_sgrow (&muscle_obstack, "[[");
13b712d7 236 obstack_escape (&muscle_obstack, bound.file);
6fbe73b6
AD
237 obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
238 extension = obstack_finish0 (&muscle_obstack);
9611cfa2
JD
239 muscle_grow (key, extension, "");
240 obstack_free (&muscle_obstack, extension);
241}
242
e5878229 243
45eebca4 244/* In the format '[[file_name:line.column]], [[file_name:line.column]]',
e5878229
AD
245 append LOC to MUSCLE. Use digraphs for special characters in each
246 file name. */
247
248static void
9611cfa2
JD
249muscle_location_grow (char const *key, location loc)
250{
9611cfa2 251 muscle_boundary_grow (key, loc.start);
eea7239a 252 muscle_grow (key, "", ", ");
9611cfa2 253 muscle_boundary_grow (key, loc.end);
9611cfa2
JD
254}
255
c1cc91bd 256#define COMMON_DECODE(Value) \
9b858541
AD
257 case '$': \
258 aver (*++(Value) == ']'); \
259 aver (*++(Value) == '['); \
260 obstack_sgrow (&muscle_obstack, "$"); \
261 break; \
262 case '@': \
263 switch (*++(Value)) \
264 { \
265 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
266 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
267 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
268 default: aver (false); break; \
269 } \
270 break; \
271 default: \
272 obstack_1grow (&muscle_obstack, *(Value)); \
f124d423
JD
273 break;
274
c1cc91bd 275/* Reverse of obstack_escape. */
f124d423 276static char *
c1cc91bd 277string_decode (char const *key)
f124d423 278{
1ad6f4da 279 char const *value = muscle_find_const (key);
f124d423
JD
280 char *value_decoded;
281 char *result;
282
f124d423
JD
283 if (!value)
284 return NULL;
285 do {
286 switch (*value)
287 {
c1cc91bd 288 COMMON_DECODE (value)
f124d423
JD
289 case '[':
290 case ']':
291 aver (false);
292 break;
293 }
294 } while (*value++);
295 value_decoded = obstack_finish (&muscle_obstack);
296 result = xstrdup (value_decoded);
297 obstack_free (&muscle_obstack, value_decoded);
298 return result;
299}
300
9611cfa2
JD
301/* Reverse of muscle_location_grow. */
302static location
c1cc91bd 303location_decode (char const *key)
9611cfa2
JD
304{
305 location loc;
306 char const *value = muscle_find_const (key);
307 aver (value);
308 aver (*value == '[');
309 aver (*++value == '[');
310 while (*++value)
311 switch (*value)
312 {
c1cc91bd 313 COMMON_DECODE (value)
9611cfa2
JD
314 case '[':
315 aver (false);
316 break;
317 case ']':
318 {
319 char *boundary_str;
320 aver (*++value == ']');
6fbe73b6 321 boundary_str = obstack_finish0 (&muscle_obstack);
9611cfa2
JD
322 switch (*++value)
323 {
324 case ',':
325 boundary_set_from_string (&loc.start, boundary_str);
326 obstack_free (&muscle_obstack, boundary_str);
327 aver (*++value == ' ');
328 aver (*++value == '[');
329 aver (*++value == '[');
330 break;
331 case '\0':
332 boundary_set_from_string (&loc.end, boundary_str);
333 obstack_free (&muscle_obstack, boundary_str);
334 return loc;
335 break;
336 default:
337 aver (false);
338 break;
339 }
340 }
341 break;
9611cfa2
JD
342 }
343 aver (false);
344 return loc;
345}
346
347void
348muscle_user_name_list_grow (char const *key, char const *user_name,
349 location loc)
350{
351 muscle_grow (key, "[[[[", ",");
352 muscle_grow (key, user_name, "");
353 muscle_grow (key, "]], ", "");
354 muscle_location_grow (key, loc);
355 muscle_grow (key, "]]", "");
356}
357
bc603897
AD
358
359/** Return an allocated string that represents the %define directive
360 that performs the assignment.
361
362 @param assignment "VAR", or "VAR=VAL".
363 @param value default value if VAL \a assignment has no '='.
364
365 For instance:
366 "foo", NULL => "%define foo"
367 "foo", "baz" => "%define foo baz"
368 "foo=bar", NULL => "%define foo bar"
369 "foo=bar", "baz" => "%define foo bar"
370 "foo=", NULL => "%define foo"
371 "foo=", "baz" => "%define foo"
372 */
373
53f8e409
AD
374static
375char *
376define_directive (char const *assignment, char const *value)
377{
bc603897
AD
378 char *eq = strchr (assignment, '=');
379 char const *fmt = !eq && value && *value ? "%%define %s %s" : "%%define %s";
53f8e409
AD
380 char *res = xmalloc (strlen (fmt) + strlen (assignment)
381 + (value ? strlen (value) : 0));
382 sprintf (res, fmt, assignment, value);
bc603897
AD
383 eq = strchr (res, '=');
384 if (eq)
385 *eq = eq[1] ? ' ' : '\0';
53f8e409
AD
386 return res;
387}
388
171ad99d 389/** If the \a variable name is obsolete, return the name to use,
bc603897
AD
390 * otherwise \a variable. If the \a value is obsolete, update it too.
391 *
392 * Allocates the returned value. */
171ad99d 393static
bc603897 394char *
53f8e409
AD
395muscle_percent_variable_update (char const *variable, location variable_loc,
396 char const **value)
171ad99d
AD
397{
398 typedef struct
399 {
400 const char *obsolete;
401 const char *updated;
402 } conversion_type;
403 const conversion_type conversion[] =
404 {
405 { "api.push_pull", "api.push-pull", },
2a6b66c5 406 { "api.tokens.prefix", "api.token.prefix", },
f9f1b3eb 407 { "lex_symbol", "api.token.constructor", },
db8ab2be 408 { "location_type", "api.location.type", },
f3bc3386
AD
409 { "lr.default-reductions", "lr.default-reduction", },
410 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", },
411 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", },
171ad99d 412 { "namespace", "api.namespace", },
4119d1ea 413 { "stype", "api.value.type", },
bc603897
AD
414 { "variant=", "api.value.type=variant", },
415 { "variant=true", "api.value.type=variant", },
53f8e409 416 { NULL, NULL, }
171ad99d 417 };
53f8e409
AD
418 conversion_type const *c;
419 for (c = conversion; c->obsolete; ++c)
bc603897
AD
420 {
421 char const *eq = strchr (c->obsolete, '=');
422 if (eq
423 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
424 && STREQ (eq + 1, *value))
425 : STREQ (c->obsolete, variable))
426 {
427 char *old = define_directive (c->obsolete, *value);
428 char *upd = define_directive (c->updated, *value);
429 deprecated_directive (&variable_loc, old, upd);
430 free (old);
431 free (upd);
432 char *res = xstrdup (c->updated);
433 {
434 char *eq2 = strchr (res, '=');
435 if (eq2)
436 {
437 *eq2 = '\0';
438 *value = eq2 + 1;
439 }
440 }
441 return res;
442 }
53f8e409 443 }
bc603897 444 return xstrdup (variable);
171ad99d
AD
445}
446
9611cfa2 447void
2aa5b259 448muscle_percent_define_insert (char const *var, location variable_loc,
de5ab940
JD
449 char const *value,
450 muscle_percent_define_how how)
9611cfa2 451{
2aa5b259 452 /* Backward compatibility. */
53f8e409 453 char *variable = muscle_percent_variable_update (var, variable_loc, &value);
2aa5b259
AD
454 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
455 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
456 char const *syncline_name =
10659d0e 457 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
2aa5b259 458 char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
9611cfa2 459
de5ab940
JD
460 /* Command-line options are processed before the grammar file. */
461 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
462 && muscle_find_const (name))
9611cfa2 463 {
1ad6f4da 464 muscle_percent_define_how how_old = atoi (muscle_find_const (how_name));
6b1e1872 465 unsigned i = 0;
de5ab940 466 if (how_old == MUSCLE_PERCENT_DEFINE_F)
bc603897 467 goto end;
b999409e
TR
468 complain_indent (&variable_loc, complaint, &i,
469 _("%%define variable %s redefined"),
470 quote (variable));
6b1e1872 471 i += SUB_INDENT;
b999409e
TR
472 location loc = muscle_percent_define_get_loc (variable);
473 complain_indent (&loc, complaint, &i, _("previous definition"));
9611cfa2 474 }
9611cfa2 475
de5ab940 476 MUSCLE_INSERT_STRING (name, value);
9611cfa2
JD
477 muscle_insert (loc_name, "");
478 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
479 muscle_insert (syncline_name, "");
480 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
481 muscle_user_name_list_grow ("percent_define_user_variables", variable,
482 variable_loc);
de5ab940 483 MUSCLE_INSERT_INT (how_name, how);
bc603897
AD
484 end:
485 free (variable);
9611cfa2
JD
486}
487
4920ae8b
AD
488/* This is used for backward compatibility, e.g., "%define api.pure"
489 supersedes "%pure-parser". */
490void
491muscle_percent_define_ensure (char const *variable, location loc,
492 bool value)
493{
494 char const *val = value ? "" : "false";
1ad6f4da 495 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
4920ae8b 496
45eebca4
AD
497 /* %pure-parser is deprecated in favor of '%define api.pure', so use
498 '%define api.pure' in a backward-compatible manner here. First,
4920ae8b
AD
499 don't complain if %pure-parser is specified multiple times. */
500 if (!muscle_find_const (name))
de5ab940
JD
501 muscle_percent_define_insert (variable, loc, val,
502 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
503 /* In all cases, use api.pure now so that the backend doesn't complain if
504 the skeleton ignores api.pure, but do warn now if there's a previous
505 conflicting definition from an actual %define. */
506 if (muscle_percent_define_flag_if (variable) != value)
de5ab940
JD
507 muscle_percent_define_insert (variable, loc, val,
508 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
509}
510
f124d423
JD
511char *
512muscle_percent_define_get (char const *variable)
513{
1ad6f4da
AD
514 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
515 char const *usage_name =
516 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
517 char *value = string_decode (name);
f124d423
JD
518 if (!value)
519 value = xstrdup ("");
1ad6f4da
AD
520
521 muscle_insert (usage_name, "");
f124d423
JD
522 return value;
523}
524
35b8730d
JD
525location
526muscle_percent_define_get_loc (char const *variable)
527{
1ad6f4da 528 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
35b8730d 529 if (!muscle_find_const (loc_name))
bb8e56ff 530 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 531 "muscle_percent_define_get_loc", quote (variable));
c1cc91bd 532 return location_decode (loc_name);
35b8730d
JD
533}
534
535char const *
536muscle_percent_define_get_syncline (char const *variable)
537{
1ad6f4da 538 char const *syncline_name =
10659d0e 539 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
1ad6f4da 540 char const *syncline = muscle_find_const (syncline_name);
35b8730d 541 if (!syncline)
bb8e56ff 542 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 543 "muscle_percent_define_get_syncline", quote (variable));
35b8730d
JD
544 return syncline;
545}
546
f124d423
JD
547bool
548muscle_percent_define_ifdef (char const *variable)
549{
1ad6f4da
AD
550 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
551 char const *usage_name =
10659d0e 552 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
1ad6f4da 553 char const *value = muscle_find_const (name);
f124d423
JD
554 if (value)
555 {
556 muscle_insert (usage_name, "");
557 return true;
558 }
559
560 return false;
561}
562
9611cfa2
JD
563bool
564muscle_percent_define_flag_if (char const *variable)
565{
1ad6f4da 566 char const *invalid_boolean_name =
10659d0e 567 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
1ad6f4da 568 bool result = false;
9611cfa2 569
f124d423 570 if (muscle_percent_define_ifdef (variable))
9611cfa2 571 {
f124d423 572 char *value = muscle_percent_define_get (variable);
f518dbaf 573 if (value[0] == '\0' || STREQ (value, "true"))
9611cfa2 574 result = true;
f518dbaf 575 else if (STREQ (value, "false"))
9611cfa2 576 result = false;
cbd50549
JD
577 else if (!muscle_find_const (invalid_boolean_name))
578 {
579 muscle_insert (invalid_boolean_name, "");
6fb8b256 580 location loc = muscle_percent_define_get_loc (variable);
bb8e56ff
TR
581 complain (&loc, complaint,
582 _("invalid value for %%define Boolean variable %s"),
583 quote (variable));
cbd50549 584 }
f124d423 585 free (value);
9611cfa2
JD
586 }
587 else
bb8e56ff 588 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 589 "muscle_percent_define_flag", quote (variable));
9611cfa2 590
9611cfa2
JD
591 return result;
592}
593
594void
595muscle_percent_define_default (char const *variable, char const *value)
596{
1ad6f4da
AD
597 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
598 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
599 char const *syncline_name =
10659d0e 600 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
9611cfa2
JD
601 if (!muscle_find_const (name))
602 {
603 location loc;
604 MUSCLE_INSERT_STRING (name, value);
92822aff
JD
605 loc.start.file = loc.end.file = "<default value>";
606 loc.start.line = loc.end.line = -1;
607 loc.start.column = loc.end.column = -1;
9611cfa2
JD
608 muscle_insert (loc_name, "");
609 muscle_location_grow (loc_name, loc);
35b8730d 610 muscle_insert (syncline_name, "");
9611cfa2
JD
611 }
612}
613
f124d423 614void
b1a81613 615muscle_percent_define_check_values (char const * const *values)
f124d423 616{
b1a81613
JD
617 for (; *values; ++values)
618 {
f4909773 619 char const * const *variablep = values;
1ad6f4da
AD
620 char const *name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
621 char *value = string_decode (name);
b1a81613
JD
622 if (value)
623 {
b1a81613
JD
624 for (++values; *values; ++values)
625 {
f518dbaf 626 if (STREQ (value, *values))
f4909773
JD
627 break;
628 }
629 if (!*values)
630 {
a974c1ec 631 unsigned i = 0;
f4909773 632 location loc = muscle_percent_define_get_loc (*variablep);
b999409e
TR
633 complain_indent (&loc, complaint, &i,
634 _("invalid value for %%define variable %s: %s"),
635 quote (*variablep), quote_n (1, value));
a974c1ec 636 i += SUB_INDENT;
f4909773 637 for (values = variablep + 1; *values; ++values)
219458e2 638 complain_indent (&loc, complaint | no_caret | silent, &i,
ea9e670d 639 _("accepted value: %s"), quote (*values));
f4909773
JD
640 }
641 else
642 {
643 while (*values)
644 ++values;
b1a81613 645 }
b1a81613
JD
646 free (value);
647 }
648 else
bb8e56ff 649 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 650 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 651 }
f124d423
JD
652}
653
9611cfa2
JD
654void
655muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
656 char const *code, location code_loc)
657{
1ad6f4da 658 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
659 muscle_code_grow (name, code, code_loc);
660 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
661 qualifier_loc);
662}
663
664
ae7453f2
AD
665/*------------------------------------------------.
666| Output the definition of ENTRY as a m4_define. |
667`------------------------------------------------*/
be2a1a68 668
e00b6826 669static inline bool
8322e8f5 670muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68 671{
1ad6f4da
AD
672 fprintf (out,
673 "m4_define([b4_%s],\n"
674 "[[%s]])\n\n\n", entry->key, entry->value);
e00b6826
PE
675 return true;
676}
677
678static bool
679muscle_m4_output_processor (void *entry, void *out)
680{
681 return muscle_m4_output (entry, out);
be2a1a68
AD
682}
683
684
be2a1a68
AD
685void
686muscles_m4_output (FILE *out)
687{
e00b6826 688 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 689}