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