]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
Provide an additional sub-message for clarity.
[bison.git] / src / muscle-tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
4920ae8b
AD
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 Free Software Foundation, Inc.
f753cd62
MA
5
6 This file is part of Bison, the GNU Compiler Compiler.
7
f16b0819 8 This program is free software: you can redistribute it and/or modify
f753cd62 9 it under the terms of the GNU General Public License as published by
f16b0819
PE
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
f753cd62 12
f16b0819 13 This program is distributed in the hope that it will be useful,
f753cd62
MA
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
f16b0819 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
f753cd62 20
2cec9080 21#include <config.h>
f753cd62 22#include "system.h"
8322e8f5
PE
23
24#include <hash.h>
25#include <quotearg.h>
26
9611cfa2 27#include "complain.h"
f753cd62 28#include "files.h"
00f5d575 29#include "muscle-tab.h"
f508cb0a 30#include "getargs.h"
f753cd62 31
eb095650
PE
32/* A key-value pair, along with storage that can be reclaimed when
33 this pair is no longer needed. */
8322e8f5
PE
34typedef struct
35{
eb095650
PE
36 char const *key;
37 char const *value;
38 char *storage;
8322e8f5 39} muscle_entry;
592e8d4d
AD
40
41/* An obstack used to create some entries. */
42struct obstack muscle_obstack;
43
beda758b
AD
44/* Initial capacity of muscles hash table. */
45#define HT_INITIAL_CAPACITY 257
f753cd62 46
04098407 47static struct hash_table *muscle_table = NULL;
f753cd62 48
beda758b
AD
49static bool
50hash_compare_muscles (void const *x, void const *y)
f753cd62 51{
8322e8f5
PE
52 muscle_entry const *m1 = x;
53 muscle_entry const *m2 = y;
5dd5fd4a 54 return strcmp (m1->key, m2->key) == 0;
f753cd62
MA
55}
56
233a88ad
PE
57static size_t
58hash_muscle (const void *x, size_t tablesize)
f753cd62 59{
8322e8f5 60 muscle_entry const *m = x;
beda758b 61 return hash_string (m->key, tablesize);
f753cd62
MA
62}
63
592e8d4d
AD
64/*-----------------------------------------------------------------.
65| Create the MUSCLE_TABLE, and initialize it with default values. |
66| Also set up the MUSCLE_OBSTACK. |
67`-----------------------------------------------------------------*/
68
eb095650
PE
69static void
70muscle_entry_free (void *entry)
71{
72 muscle_entry *mentry = entry;
73 free (mentry->storage);
74 free (mentry);
75}
76
f753cd62
MA
77void
78muscle_init (void)
79{
ae7453f2
AD
80 /* Initialize the muscle obstack. */
81 obstack_init (&muscle_obstack);
82
beda758b 83 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
eb095650 84 hash_compare_muscles, muscle_entry_free);
f753cd62
MA
85
86 /* Version and input file. */
ae7453f2 87 MUSCLE_INSERT_STRING ("version", VERSION);
f753cd62
MA
88}
89
592e8d4d
AD
90
91/*------------------------------------------------------------.
92| Free all the memory consumed by the muscle machinery only. |
93`------------------------------------------------------------*/
94
95void
96muscle_free (void)
97{
98 hash_free (muscle_table);
99 obstack_free (&muscle_obstack, NULL);
100}
101
102
103
ae7453f2
AD
104/*------------------------------------------------------------.
105| Insert (KEY, VALUE). If KEY already existed, overwrite the |
106| previous value. |
107`------------------------------------------------------------*/
108
a870c567 109void
eb095650 110muscle_insert (char const *key, char const *value)
f753cd62 111{
8322e8f5 112 muscle_entry probe;
da2a7671 113 muscle_entry *entry;
e9bca3ad 114
ae7453f2
AD
115 probe.key = key;
116 entry = hash_lookup (muscle_table, &probe);
beda758b
AD
117
118 if (!entry)
119 {
120 /* First insertion in the hash. */
da2a7671 121 entry = xmalloc (sizeof *entry);
beda758b 122 entry->key = key;
04d1e39d
AD
123 if (!hash_insert (muscle_table, entry))
124 xalloc_die ();
beda758b 125 }
4502eadc
JD
126 else
127 free (entry->storage);
beda758b 128 entry->value = value;
4502eadc 129 entry->storage = NULL;
f753cd62
MA
130}
131
ae7453f2
AD
132
133/*-------------------------------------------------------------------.
ff5150d9
PE
134| Append VALUE to the current value of KEY. If KEY did not already |
135| exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
136| associated value. Copy VALUE and SEPARATOR. |
ae7453f2
AD
137`-------------------------------------------------------------------*/
138
139void
140muscle_grow (const char *key, const char *val, const char *separator)
141{
8322e8f5
PE
142 muscle_entry probe;
143 muscle_entry *entry = NULL;
ae7453f2
AD
144
145 probe.key = key;
146 entry = hash_lookup (muscle_table, &probe);
147
148 if (!entry)
149 {
150 /* First insertion in the hash. */
da2a7671 151 entry = xmalloc (sizeof *entry);
ae7453f2 152 entry->key = key;
04d1e39d
AD
153 if (!hash_insert (muscle_table, entry))
154 xalloc_die ();
eb095650 155 entry->value = entry->storage = xstrdup (val);
ae7453f2
AD
156 }
157 else
158 {
159 /* Grow the current value. */
160 char *new_val;
ae7453f2 161 obstack_sgrow (&muscle_obstack, entry->value);
eb095650 162 free (entry->storage);
ae7453f2
AD
163 obstack_sgrow (&muscle_obstack, separator);
164 obstack_sgrow (&muscle_obstack, val);
165 obstack_1grow (&muscle_obstack, 0);
166 new_val = obstack_finish (&muscle_obstack);
eb095650 167 entry->value = entry->storage = xstrdup (new_val);
ae7453f2
AD
168 obstack_free (&muscle_obstack, new_val);
169 }
170}
171
cd3684cf 172/*------------------------------------------------------------------.
35b8730d
JD
173| Using muscle_grow, append a synchronization line for the location |
174| LOC to the current value of KEY. |
cd3684cf
AD
175`------------------------------------------------------------------*/
176
35b8730d
JD
177static void
178muscle_syncline_grow (char const *key, location loc)
cd3684cf
AD
179{
180 char *extension = NULL;
05ac60f3 181 obstack_fgrow1 (&muscle_obstack, "]b4_syncline(%d, [[", loc.start.line);
cd3684cf
AD
182 MUSCLE_OBSTACK_SGROW (&muscle_obstack,
183 quotearg_style (c_quoting_style, loc.start.file));
35b8730d 184 obstack_sgrow (&muscle_obstack, "]])[");
cd3684cf
AD
185 obstack_1grow (&muscle_obstack, 0);
186 extension = obstack_finish (&muscle_obstack);
187 muscle_grow (key, extension, "");
eb095650 188 obstack_free (&muscle_obstack, extension);
cd3684cf
AD
189}
190
35b8730d
JD
191/*------------------------------------------------------------------.
192| Append VALUE to the current value of KEY, using muscle_grow. But |
193| in addition, issue a synchronization line for the location LOC |
194| using muscle_syncline_grow. |
195`------------------------------------------------------------------*/
196
197void
198muscle_code_grow (const char *key, const char *val, location loc)
199{
200 muscle_syncline_grow (key, loc);
201 muscle_grow (key, val, "\n");
202}
203
cd3684cf 204
ae7453f2
AD
205void muscle_pair_list_grow (const char *muscle,
206 const char *a1, const char *a2)
207{
66d30cd4 208 char *pair;
7ecec4dd
JD
209 obstack_sgrow (&muscle_obstack, "[[[");
210 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a1);
211 obstack_sgrow (&muscle_obstack, "]], [[");
212 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a2);
213 obstack_sgrow (&muscle_obstack, "]]]");
ae7453f2 214 obstack_1grow (&muscle_obstack, 0);
66d30cd4
AD
215 pair = obstack_finish (&muscle_obstack);
216 muscle_grow (muscle, pair, ",\n");
217 obstack_free (&muscle_obstack, pair);
ae7453f2
AD
218}
219
7eb8a0bc
JD
220
221/*----------------------------------------------------------------------------.
222| Find the value of muscle KEY. Unlike MUSCLE_FIND, this is always reliable |
223| to determine whether KEY has a value. |
224`----------------------------------------------------------------------------*/
225
226char const *
227muscle_find_const (char const *key)
228{
229 muscle_entry probe;
230 muscle_entry *result = NULL;
231
232 probe.key = key;
233 result = hash_lookup (muscle_table, &probe);
234 if (result)
235 return result->value;
236 return NULL;
237}
238
239
4502eadc
JD
240/*----------------------------------------------------------------------------.
241| Find the value of muscle KEY. Abort if muscle_insert was invoked more |
242| recently than muscle_grow for KEY since muscle_find can't return a |
243| char const *. |
244`----------------------------------------------------------------------------*/
ae7453f2 245
ff5150d9 246char *
7eb8a0bc 247muscle_find (char const *key)
f753cd62 248{
8322e8f5
PE
249 muscle_entry probe;
250 muscle_entry *result = NULL;
e9bca3ad 251
ae7453f2
AD
252 probe.key = key;
253 result = hash_lookup (muscle_table, &probe);
4502eadc
JD
254 if (result)
255 {
256 aver (result->value == result->storage);
257 return result->storage;
258 }
259 return NULL;
f753cd62 260}
be2a1a68
AD
261
262
9611cfa2
JD
263void
264muscle_boundary_grow (char const *key, boundary bound)
265{
266 char *extension;
267 MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file);
268 obstack_1grow (&muscle_obstack, ':');
269 obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
270 obstack_1grow (&muscle_obstack, '.');
271 obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
272 obstack_1grow (&muscle_obstack, '\0');
273 extension = obstack_finish (&muscle_obstack);
274 muscle_grow (key, extension, "");
275 obstack_free (&muscle_obstack, extension);
276}
277
278void
279muscle_location_grow (char const *key, location loc)
280{
281 muscle_grow (key, "[[", "");
282 muscle_boundary_grow (key, loc.start);
283 muscle_grow (key, "]], [[", "");
284 muscle_boundary_grow (key, loc.end);
285 muscle_grow (key, "]]", "");
286}
287
f124d423
JD
288#define MUSCLE_COMMON_DECODE(Value) \
289 case '$': \
290 aver (*++(Value) == ']'); \
291 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 MUSCLE_OBSTACK_SGROW. */
308static char *
309muscle_string_decode (char const *key)
310{
311 char const *value;
312 char *value_decoded;
313 char *result;
314
315 value = muscle_find_const (key);
316 if (!value)
317 return NULL;
318 do {
319 switch (*value)
320 {
321 MUSCLE_COMMON_DECODE (value)
322 case '[':
323 case ']':
324 aver (false);
325 break;
326 }
327 } while (*value++);
328 value_decoded = obstack_finish (&muscle_obstack);
329 result = xstrdup (value_decoded);
330 obstack_free (&muscle_obstack, value_decoded);
331 return result;
332}
333
9611cfa2
JD
334/* Reverse of muscle_location_grow. */
335static location
336muscle_location_decode (char const *key)
337{
338 location loc;
339 char const *value = muscle_find_const (key);
340 aver (value);
341 aver (*value == '[');
342 aver (*++value == '[');
343 while (*++value)
344 switch (*value)
345 {
f124d423 346 MUSCLE_COMMON_DECODE (value)
9611cfa2
JD
347 case '[':
348 aver (false);
349 break;
350 case ']':
351 {
352 char *boundary_str;
353 aver (*++value == ']');
354 obstack_1grow (&muscle_obstack, '\0');
355 boundary_str = obstack_finish (&muscle_obstack);
356 switch (*++value)
357 {
358 case ',':
359 boundary_set_from_string (&loc.start, boundary_str);
360 obstack_free (&muscle_obstack, boundary_str);
361 aver (*++value == ' ');
362 aver (*++value == '[');
363 aver (*++value == '[');
364 break;
365 case '\0':
366 boundary_set_from_string (&loc.end, boundary_str);
367 obstack_free (&muscle_obstack, boundary_str);
368 return loc;
369 break;
370 default:
371 aver (false);
372 break;
373 }
374 }
375 break;
9611cfa2
JD
376 }
377 aver (false);
378 return loc;
379}
380
381void
382muscle_user_name_list_grow (char const *key, char const *user_name,
383 location loc)
384{
385 muscle_grow (key, "[[[[", ",");
386 muscle_grow (key, user_name, "");
387 muscle_grow (key, "]], ", "");
388 muscle_location_grow (key, loc);
389 muscle_grow (key, "]]", "");
390}
391
171ad99d
AD
392/** If the \a variable name is obsolete, return the name to use,
393 * otherwise \a variable. */
394static
395char const *
396muscle_percent_variable_update (char const *variable)
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", },
406 { "lr.keep_unreachable_states", "lr.keep-unreachable-states", },
407 { "namespace", "api.namespace", },
408 };
409 int i;
410 for (i = 0; i < sizeof conversion / sizeof *conversion; ++i)
411 if (!strcmp (conversion[i].obsolete, variable))
412 return conversion[i].updated;
413 return variable;
414}
415
9611cfa2
JD
416#define MUSCLE_USER_NAME_CONVERT(NAME, PREFIX, USER_NAME, SUFFIX) \
417do { \
418 char *tmp; \
419 size_t length = strlen ((USER_NAME)); \
420 tmp = xmalloc (sizeof (PREFIX) - 1 + length + sizeof (SUFFIX)); \
421 strcpy (tmp, (PREFIX)); \
422 strcpy (tmp + sizeof (PREFIX) - 1, (USER_NAME)); \
423 strcpy (tmp + sizeof (PREFIX) - 1 + length, (SUFFIX)); \
424 (NAME) = uniqstr_new (tmp); \
425 free (tmp); \
426} while (0)
427
428void
429muscle_percent_define_insert (char const *variable, location variable_loc,
de5ab940
JD
430 char const *value,
431 muscle_percent_define_how how)
9611cfa2
JD
432{
433 char const *name;
434 char const *loc_name;
35b8730d 435 char const *syncline_name;
de5ab940 436 char const *how_name;
9611cfa2 437
67212941 438 /* Permit certain names with underscores for backward compatibility. */
171ad99d 439 variable = muscle_percent_variable_update (variable);
67212941 440
9611cfa2
JD
441 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
442 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
443 MUSCLE_USER_NAME_CONVERT (syncline_name,
444 "percent_define_syncline(", variable, ")");
de5ab940 445 MUSCLE_USER_NAME_CONVERT (how_name, "percent_define_how(", variable, ")");
9611cfa2 446
de5ab940
JD
447 /* Command-line options are processed before the grammar file. */
448 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
449 && muscle_find_const (name))
9611cfa2 450 {
de5ab940
JD
451 muscle_percent_define_how how_old =
452 atoi (muscle_find_const (how_name));
453 if (how_old == MUSCLE_PERCENT_DEFINE_F)
171ad99d 454 return;
0b6d43c5
JD
455 complain_at (variable_loc, _("%s `%s' redefined"),
456 "%define variable", variable);
457 complain_at (muscle_percent_define_get_loc (variable),
de5ab940 458 _("previous definition"));
9611cfa2 459 }
9611cfa2 460
de5ab940 461 MUSCLE_INSERT_STRING (name, value);
9611cfa2
JD
462 muscle_insert (loc_name, "");
463 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
464 muscle_insert (syncline_name, "");
465 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
466 muscle_user_name_list_grow ("percent_define_user_variables", variable,
467 variable_loc);
de5ab940 468 MUSCLE_INSERT_INT (how_name, how);
9611cfa2
JD
469}
470
4920ae8b
AD
471/* This is used for backward compatibility, e.g., "%define api.pure"
472 supersedes "%pure-parser". */
473void
474muscle_percent_define_ensure (char const *variable, location loc,
475 bool value)
476{
477 char const *val = value ? "" : "false";
478 char const *name;
479 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
480
481 /* %pure-parser is deprecated in favor of `%define api.pure', so use
482 `%define api.pure' in a backward-compatible manner here. First,
483 don't complain if %pure-parser is specified multiple times. */
484 if (!muscle_find_const (name))
de5ab940
JD
485 muscle_percent_define_insert (variable, loc, val,
486 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
487 /* In all cases, use api.pure now so that the backend doesn't complain if
488 the skeleton ignores api.pure, but do warn now if there's a previous
489 conflicting definition from an actual %define. */
490 if (muscle_percent_define_flag_if (variable) != value)
de5ab940
JD
491 muscle_percent_define_insert (variable, loc, val,
492 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
493}
494
f124d423
JD
495char *
496muscle_percent_define_get (char const *variable)
497{
498 char const *name;
499 char const *usage_name;
500 char *value;
501
502 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
503 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
504 variable, ")");
505
506 muscle_insert (usage_name, "");
507 value = muscle_string_decode (name);
508 if (!value)
509 value = xstrdup ("");
510 return value;
511}
512
35b8730d
JD
513location
514muscle_percent_define_get_loc (char const *variable)
515{
516 char const *loc_name;
517 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
518 if (!muscle_find_const (loc_name))
519 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_loc"),
520 variable);
521 return muscle_location_decode (loc_name);
522}
523
524char const *
525muscle_percent_define_get_syncline (char const *variable)
526{
527 char const *syncline_name;
528 char const *syncline;
529 MUSCLE_USER_NAME_CONVERT (syncline_name,
530 "percent_define_syncline(", variable, ")");
531 syncline = muscle_find_const (syncline_name);
532 if (!syncline)
533 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_syncline"),
534 variable);
535 return syncline;
536}
537
f124d423
JD
538bool
539muscle_percent_define_ifdef (char const *variable)
540{
541 char const *name;
542 char const *usage_name;
543 char const *value;
544
545 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
546 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
547 variable, ")");
548
549 value = muscle_find_const (name);
550 if (value)
551 {
552 muscle_insert (usage_name, "");
553 return true;
554 }
555
556 return false;
557}
558
9611cfa2
JD
559bool
560muscle_percent_define_flag_if (char const *variable)
561{
cbd50549 562 char const *invalid_boolean_name;
9611cfa2
JD
563 bool result = false;
564
cbd50549
JD
565 MUSCLE_USER_NAME_CONVERT (invalid_boolean_name,
566 "percent_define_invalid_boolean(", variable, ")");
9611cfa2 567
f124d423 568 if (muscle_percent_define_ifdef (variable))
9611cfa2 569 {
f124d423 570 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
571 if (value[0] == '\0' || 0 == strcmp (value, "true"))
572 result = true;
573 else if (0 == strcmp (value, "false"))
574 result = false;
cbd50549
JD
575 else if (!muscle_find_const (invalid_boolean_name))
576 {
577 muscle_insert (invalid_boolean_name, "");
35b8730d 578 complain_at(muscle_percent_define_get_loc (variable),
922bdd7f 579 _("invalid value for %%define Boolean variable `%s'"),
cbd50549
JD
580 variable);
581 }
f124d423 582 free (value);
9611cfa2
JD
583 }
584 else
585 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
586 variable);
587
9611cfa2
JD
588 return result;
589}
590
591void
592muscle_percent_define_default (char const *variable, char const *value)
593{
594 char const *name;
595 char const *loc_name;
35b8730d 596 char const *syncline_name;
9611cfa2
JD
597 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
598 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
599 MUSCLE_USER_NAME_CONVERT (syncline_name,
600 "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;
b1a81613 620 char const *name;
b1a81613
JD
621 char *value;
622
f4909773 623 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", *variablep, ")");
b1a81613
JD
624
625 value = muscle_string_decode (name);
626 if (value)
627 {
b1a81613
JD
628 for (++values; *values; ++values)
629 {
630 if (0 == strcmp (value, *values))
f4909773
JD
631 break;
632 }
633 if (!*values)
634 {
635 location loc = muscle_percent_define_get_loc (*variablep);
636 complain_at(loc,
637 _("invalid value for %%define variable `%s': `%s'"),
638 *variablep, value);
639 for (values = variablep + 1; *values; ++values)
640 complain_at (loc, _("accepted value: `%s'"), *values);
641 }
642 else
643 {
644 while (*values)
645 ++values;
b1a81613 646 }
b1a81613
JD
647 free (value);
648 }
649 else
f4909773
JD
650 fatal(_("undefined %%define variable `%s' passed to"
651 " muscle_percent_define_check_values"),
652 *variablep);
b1a81613 653 }
f124d423
JD
654}
655
9611cfa2
JD
656void
657muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
658 char const *code, location code_loc)
659{
660 char const *name;
661 MUSCLE_USER_NAME_CONVERT (name, "percent_code(", qualifier, ")");
662 muscle_code_grow (name, code, code_loc);
663 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
664 qualifier_loc);
665}
666
667
ae7453f2
AD
668/*------------------------------------------------.
669| Output the definition of ENTRY as a m4_define. |
670`------------------------------------------------*/
be2a1a68 671
e00b6826 672static inline bool
8322e8f5 673muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
674{
675 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 676 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
677 return true;
678}
679
680static bool
681muscle_m4_output_processor (void *entry, void *out)
682{
683 return muscle_m4_output (entry, out);
be2a1a68
AD
684}
685
686
ae7453f2
AD
687/*----------------------------------------------------------------.
688| Output the definition of all the current muscles into a list of |
689| m4_defines. |
690`----------------------------------------------------------------*/
be2a1a68
AD
691
692void
693muscles_m4_output (FILE *out)
694{
e00b6826 695 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 696}