]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
2009-08-19 Akim Demaille <demaille@gostai.com>
[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
392#define MUSCLE_USER_NAME_CONVERT(NAME, PREFIX, USER_NAME, SUFFIX) \
393do { \
394 char *tmp; \
395 size_t length = strlen ((USER_NAME)); \
396 tmp = xmalloc (sizeof (PREFIX) - 1 + length + sizeof (SUFFIX)); \
397 strcpy (tmp, (PREFIX)); \
398 strcpy (tmp + sizeof (PREFIX) - 1, (USER_NAME)); \
399 strcpy (tmp + sizeof (PREFIX) - 1 + length, (SUFFIX)); \
400 (NAME) = uniqstr_new (tmp); \
401 free (tmp); \
402} while (0)
403
404void
405muscle_percent_define_insert (char const *variable, location variable_loc,
de5ab940
JD
406 char const *value,
407 muscle_percent_define_how how)
9611cfa2 408{
67212941 409 char *variable_tr = NULL;
9611cfa2
JD
410 char const *name;
411 char const *loc_name;
35b8730d 412 char const *syncline_name;
de5ab940 413 char const *how_name;
9611cfa2 414
67212941
JD
415 /* Permit certain names with underscores for backward compatibility. */
416 if (0 == strcmp (variable, "api.push_pull")
417 || 0 == strcmp (variable, "lr.keep_unreachable_states"))
418 {
419 variable_tr = strdup (variable);
420 tr (variable_tr, '_', '-');
421 variable = variable_tr;
422 }
423
9611cfa2
JD
424 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
425 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
426 MUSCLE_USER_NAME_CONVERT (syncline_name,
427 "percent_define_syncline(", variable, ")");
de5ab940 428 MUSCLE_USER_NAME_CONVERT (how_name, "percent_define_how(", variable, ")");
9611cfa2 429
de5ab940
JD
430 /* Command-line options are processed before the grammar file. */
431 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
432 && muscle_find_const (name))
9611cfa2 433 {
de5ab940
JD
434 muscle_percent_define_how how_old =
435 atoi (muscle_find_const (how_name));
436 if (how_old == MUSCLE_PERCENT_DEFINE_F)
437 {
438 free (variable_tr);
439 return;
440 }
0b6d43c5
JD
441 complain_at (variable_loc, _("%s `%s' redefined"),
442 "%define variable", variable);
443 complain_at (muscle_percent_define_get_loc (variable),
de5ab940 444 _("previous definition"));
9611cfa2 445 }
9611cfa2 446
de5ab940 447 MUSCLE_INSERT_STRING (name, value);
9611cfa2
JD
448 muscle_insert (loc_name, "");
449 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
450 muscle_insert (syncline_name, "");
451 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
452 muscle_user_name_list_grow ("percent_define_user_variables", variable,
453 variable_loc);
de5ab940 454 MUSCLE_INSERT_INT (how_name, how);
67212941
JD
455
456 free (variable_tr);
9611cfa2
JD
457}
458
4920ae8b
AD
459/* This is used for backward compatibility, e.g., "%define api.pure"
460 supersedes "%pure-parser". */
461void
462muscle_percent_define_ensure (char const *variable, location loc,
463 bool value)
464{
465 char const *val = value ? "" : "false";
466 char const *name;
467 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
468
469 /* %pure-parser is deprecated in favor of `%define api.pure', so use
470 `%define api.pure' in a backward-compatible manner here. First,
471 don't complain if %pure-parser is specified multiple times. */
472 if (!muscle_find_const (name))
de5ab940
JD
473 muscle_percent_define_insert (variable, loc, val,
474 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
475 /* In all cases, use api.pure now so that the backend doesn't complain if
476 the skeleton ignores api.pure, but do warn now if there's a previous
477 conflicting definition from an actual %define. */
478 if (muscle_percent_define_flag_if (variable) != value)
de5ab940
JD
479 muscle_percent_define_insert (variable, loc, val,
480 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
481}
482
f124d423
JD
483char *
484muscle_percent_define_get (char const *variable)
485{
486 char const *name;
487 char const *usage_name;
488 char *value;
489
490 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
491 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
492 variable, ")");
493
494 muscle_insert (usage_name, "");
495 value = muscle_string_decode (name);
496 if (!value)
497 value = xstrdup ("");
498 return value;
499}
500
35b8730d
JD
501location
502muscle_percent_define_get_loc (char const *variable)
503{
504 char const *loc_name;
505 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
506 if (!muscle_find_const (loc_name))
507 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_loc"),
508 variable);
509 return muscle_location_decode (loc_name);
510}
511
512char const *
513muscle_percent_define_get_syncline (char const *variable)
514{
515 char const *syncline_name;
516 char const *syncline;
517 MUSCLE_USER_NAME_CONVERT (syncline_name,
518 "percent_define_syncline(", variable, ")");
519 syncline = muscle_find_const (syncline_name);
520 if (!syncline)
521 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_syncline"),
522 variable);
523 return syncline;
524}
525
f124d423
JD
526bool
527muscle_percent_define_ifdef (char const *variable)
528{
529 char const *name;
530 char const *usage_name;
531 char const *value;
532
533 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
534 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
535 variable, ")");
536
537 value = muscle_find_const (name);
538 if (value)
539 {
540 muscle_insert (usage_name, "");
541 return true;
542 }
543
544 return false;
545}
546
9611cfa2
JD
547bool
548muscle_percent_define_flag_if (char const *variable)
549{
cbd50549 550 char const *invalid_boolean_name;
9611cfa2
JD
551 bool result = false;
552
cbd50549
JD
553 MUSCLE_USER_NAME_CONVERT (invalid_boolean_name,
554 "percent_define_invalid_boolean(", variable, ")");
9611cfa2 555
f124d423 556 if (muscle_percent_define_ifdef (variable))
9611cfa2 557 {
f124d423 558 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
559 if (value[0] == '\0' || 0 == strcmp (value, "true"))
560 result = true;
561 else if (0 == strcmp (value, "false"))
562 result = false;
cbd50549
JD
563 else if (!muscle_find_const (invalid_boolean_name))
564 {
565 muscle_insert (invalid_boolean_name, "");
35b8730d 566 complain_at(muscle_percent_define_get_loc (variable),
922bdd7f 567 _("invalid value for %%define Boolean variable `%s'"),
cbd50549
JD
568 variable);
569 }
f124d423 570 free (value);
9611cfa2
JD
571 }
572 else
573 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
574 variable);
575
9611cfa2
JD
576 return result;
577}
578
579void
580muscle_percent_define_default (char const *variable, char const *value)
581{
582 char const *name;
583 char const *loc_name;
35b8730d 584 char const *syncline_name;
9611cfa2
JD
585 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
586 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
587 MUSCLE_USER_NAME_CONVERT (syncline_name,
588 "percent_define_syncline(", variable, ")");
9611cfa2
JD
589 if (!muscle_find_const (name))
590 {
591 location loc;
592 MUSCLE_INSERT_STRING (name, value);
92822aff
JD
593 loc.start.file = loc.end.file = "<default value>";
594 loc.start.line = loc.end.line = -1;
595 loc.start.column = loc.end.column = -1;
9611cfa2
JD
596 muscle_insert (loc_name, "");
597 muscle_location_grow (loc_name, loc);
35b8730d 598 muscle_insert (syncline_name, "");
9611cfa2
JD
599 }
600}
601
f124d423 602void
b1a81613 603muscle_percent_define_check_values (char const * const *values)
f124d423 604{
b1a81613
JD
605 for (; *values; ++values)
606 {
f4909773 607 char const * const *variablep = values;
b1a81613 608 char const *name;
b1a81613
JD
609 char *value;
610
f4909773 611 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", *variablep, ")");
b1a81613
JD
612
613 value = muscle_string_decode (name);
614 if (value)
615 {
b1a81613
JD
616 for (++values; *values; ++values)
617 {
618 if (0 == strcmp (value, *values))
f4909773
JD
619 break;
620 }
621 if (!*values)
622 {
623 location loc = muscle_percent_define_get_loc (*variablep);
624 complain_at(loc,
625 _("invalid value for %%define variable `%s': `%s'"),
626 *variablep, value);
627 for (values = variablep + 1; *values; ++values)
628 complain_at (loc, _("accepted value: `%s'"), *values);
629 }
630 else
631 {
632 while (*values)
633 ++values;
b1a81613 634 }
b1a81613
JD
635 free (value);
636 }
637 else
f4909773
JD
638 fatal(_("undefined %%define variable `%s' passed to"
639 " muscle_percent_define_check_values"),
640 *variablep);
b1a81613 641 }
f124d423
JD
642}
643
9611cfa2
JD
644void
645muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
646 char const *code, location code_loc)
647{
648 char const *name;
649 MUSCLE_USER_NAME_CONVERT (name, "percent_code(", qualifier, ")");
650 muscle_code_grow (name, code, code_loc);
651 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
652 qualifier_loc);
653}
654
655
ae7453f2
AD
656/*------------------------------------------------.
657| Output the definition of ENTRY as a m4_define. |
658`------------------------------------------------*/
be2a1a68 659
e00b6826 660static inline bool
8322e8f5 661muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
662{
663 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 664 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
665 return true;
666}
667
668static bool
669muscle_m4_output_processor (void *entry, void *out)
670{
671 return muscle_m4_output (entry, out);
be2a1a68
AD
672}
673
674
ae7453f2
AD
675/*----------------------------------------------------------------.
676| Output the definition of all the current muscles into a list of |
677| m4_defines. |
678`----------------------------------------------------------------*/
be2a1a68
AD
679
680void
681muscles_m4_output (FILE *out)
682{
e00b6826 683 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 684}