]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
minor refactoring in user code scanning
[bison.git] / src / muscle-tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
34136e65 3 Copyright (C) 2001-2012 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
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,
e9690142 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;
aaf63e45 180 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
0601c3bf
AD
181 obstack_quote (&muscle_obstack,
182 quotearg_style (c_quoting_style, loc.start.file));
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 204void muscle_pair_list_grow (const char *muscle,
e9690142 205 const char *a1, const char *a2)
ae7453f2 206{
66d30cd4 207 char *pair;
0601c3bf
AD
208 obstack_sgrow (&muscle_obstack, "[");
209 obstack_quote (&muscle_obstack, a1);
210 obstack_sgrow (&muscle_obstack, ", ");
211 obstack_quote (&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
e5878229
AD
262/* In the format `file_name:line.column', append BOUND to MUSCLE. Use
263 digraphs for special characters in the file name. */
264
265static void
9611cfa2
JD
266muscle_boundary_grow (char const *key, boundary bound)
267{
268 char *extension;
eea7239a 269 obstack_sgrow (&muscle_obstack, "[[");
13b712d7 270 obstack_escape (&muscle_obstack, bound.file);
9611cfa2 271 obstack_1grow (&muscle_obstack, ':');
aaf63e45 272 obstack_printf (&muscle_obstack, "%d", bound.line);
9611cfa2 273 obstack_1grow (&muscle_obstack, '.');
aaf63e45 274 obstack_printf (&muscle_obstack, "%d", bound.column);
eea7239a 275 obstack_sgrow (&muscle_obstack, "]]");
9611cfa2
JD
276 obstack_1grow (&muscle_obstack, '\0');
277 extension = obstack_finish (&muscle_obstack);
278 muscle_grow (key, extension, "");
279 obstack_free (&muscle_obstack, extension);
280}
281
e5878229
AD
282
283/* In the format `[[file_name:line.column]], [[file_name:line.column]]',
284 append LOC to MUSCLE. Use digraphs for special characters in each
285 file name. */
286
287static void
9611cfa2
JD
288muscle_location_grow (char const *key, location loc)
289{
9611cfa2 290 muscle_boundary_grow (key, loc.start);
eea7239a 291 muscle_grow (key, "", ", ");
9611cfa2 292 muscle_boundary_grow (key, loc.end);
9611cfa2
JD
293}
294
c1cc91bd 295#define COMMON_DECODE(Value) \
9b858541
AD
296 case '$': \
297 aver (*++(Value) == ']'); \
298 aver (*++(Value) == '['); \
299 obstack_sgrow (&muscle_obstack, "$"); \
300 break; \
301 case '@': \
302 switch (*++(Value)) \
303 { \
304 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
305 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
306 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
307 default: aver (false); break; \
308 } \
309 break; \
310 default: \
311 obstack_1grow (&muscle_obstack, *(Value)); \
f124d423
JD
312 break;
313
c1cc91bd 314/* Reverse of obstack_escape. */
f124d423 315static char *
c1cc91bd 316string_decode (char const *key)
f124d423
JD
317{
318 char const *value;
319 char *value_decoded;
320 char *result;
321
322 value = muscle_find_const (key);
323 if (!value)
324 return NULL;
325 do {
326 switch (*value)
327 {
c1cc91bd 328 COMMON_DECODE (value)
f124d423
JD
329 case '[':
330 case ']':
331 aver (false);
332 break;
333 }
334 } while (*value++);
335 value_decoded = obstack_finish (&muscle_obstack);
336 result = xstrdup (value_decoded);
337 obstack_free (&muscle_obstack, value_decoded);
338 return result;
339}
340
9611cfa2
JD
341/* Reverse of muscle_location_grow. */
342static location
c1cc91bd 343location_decode (char const *key)
9611cfa2
JD
344{
345 location loc;
346 char const *value = muscle_find_const (key);
347 aver (value);
348 aver (*value == '[');
349 aver (*++value == '[');
350 while (*++value)
351 switch (*value)
352 {
c1cc91bd 353 COMMON_DECODE (value)
9611cfa2
JD
354 case '[':
355 aver (false);
356 break;
357 case ']':
358 {
359 char *boundary_str;
360 aver (*++value == ']');
361 obstack_1grow (&muscle_obstack, '\0');
362 boundary_str = obstack_finish (&muscle_obstack);
363 switch (*++value)
364 {
365 case ',':
366 boundary_set_from_string (&loc.start, boundary_str);
367 obstack_free (&muscle_obstack, boundary_str);
368 aver (*++value == ' ');
369 aver (*++value == '[');
370 aver (*++value == '[');
371 break;
372 case '\0':
373 boundary_set_from_string (&loc.end, boundary_str);
374 obstack_free (&muscle_obstack, boundary_str);
375 return loc;
376 break;
377 default:
378 aver (false);
379 break;
380 }
381 }
382 break;
9611cfa2
JD
383 }
384 aver (false);
385 return loc;
386}
387
388void
389muscle_user_name_list_grow (char const *key, char const *user_name,
390 location loc)
391{
392 muscle_grow (key, "[[[[", ",");
393 muscle_grow (key, user_name, "");
394 muscle_grow (key, "]], ", "");
395 muscle_location_grow (key, loc);
396 muscle_grow (key, "]]", "");
397}
398
171ad99d
AD
399/** If the \a variable name is obsolete, return the name to use,
400 * otherwise \a variable. */
401static
402char const *
403muscle_percent_variable_update (char const *variable)
404{
405 typedef struct
406 {
407 const char *obsolete;
408 const char *updated;
409 } conversion_type;
410 const conversion_type conversion[] =
411 {
412 { "api.push_pull", "api.push-pull", },
413 { "lr.keep_unreachable_states", "lr.keep-unreachable-states", },
414 { "namespace", "api.namespace", },
415 };
416 int i;
417 for (i = 0; i < sizeof conversion / sizeof *conversion; ++i)
f518dbaf 418 if (STREQ (conversion[i].obsolete, variable))
171ad99d
AD
419 return conversion[i].updated;
420 return variable;
421}
422
9611cfa2
JD
423void
424muscle_percent_define_insert (char const *variable, location variable_loc,
de5ab940
JD
425 char const *value,
426 muscle_percent_define_how how)
9611cfa2
JD
427{
428 char const *name;
429 char const *loc_name;
35b8730d 430 char const *syncline_name;
de5ab940 431 char const *how_name;
9611cfa2 432
67212941 433 /* Permit certain names with underscores for backward compatibility. */
171ad99d 434 variable = muscle_percent_variable_update (variable);
67212941 435
10659d0e
JD
436 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
437 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
438 syncline_name =
439 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
440 how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
9611cfa2 441
de5ab940
JD
442 /* Command-line options are processed before the grammar file. */
443 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
444 && muscle_find_const (name))
9611cfa2 445 {
de5ab940
JD
446 muscle_percent_define_how how_old =
447 atoi (muscle_find_const (how_name));
448 if (how_old == MUSCLE_PERCENT_DEFINE_F)
171ad99d 449 return;
6fb8b256 450 complain_at (variable_loc, complaint, _("%%define variable %s redefined"),
4a9cd8f2 451 quote (variable));
6fb8b256
VS
452 location loc = muscle_percent_define_get_loc (variable);
453 complain_at (loc, complaint, _("previous definition"));
9611cfa2 454 }
9611cfa2 455
de5ab940 456 MUSCLE_INSERT_STRING (name, value);
9611cfa2
JD
457 muscle_insert (loc_name, "");
458 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
459 muscle_insert (syncline_name, "");
460 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
461 muscle_user_name_list_grow ("percent_define_user_variables", variable,
462 variable_loc);
de5ab940 463 MUSCLE_INSERT_INT (how_name, how);
9611cfa2
JD
464}
465
4920ae8b
AD
466/* This is used for backward compatibility, e.g., "%define api.pure"
467 supersedes "%pure-parser". */
468void
469muscle_percent_define_ensure (char const *variable, location loc,
470 bool value)
471{
472 char const *val = value ? "" : "false";
473 char const *name;
10659d0e 474 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
4920ae8b
AD
475
476 /* %pure-parser is deprecated in favor of `%define api.pure', so use
477 `%define api.pure' in a backward-compatible manner here. First,
478 don't complain if %pure-parser is specified multiple times. */
479 if (!muscle_find_const (name))
de5ab940
JD
480 muscle_percent_define_insert (variable, loc, val,
481 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
482 /* In all cases, use api.pure now so that the backend doesn't complain if
483 the skeleton ignores api.pure, but do warn now if there's a previous
484 conflicting definition from an actual %define. */
485 if (muscle_percent_define_flag_if (variable) != value)
de5ab940
JD
486 muscle_percent_define_insert (variable, loc, val,
487 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
488}
489
f124d423
JD
490char *
491muscle_percent_define_get (char const *variable)
492{
493 char const *name;
494 char const *usage_name;
495 char *value;
496
10659d0e
JD
497 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
498 usage_name = UNIQSTR_CONCAT ("percent_define_bison_variables(",
499 variable, ")");
f124d423
JD
500
501 muscle_insert (usage_name, "");
c1cc91bd 502 value = string_decode (name);
f124d423
JD
503 if (!value)
504 value = xstrdup ("");
505 return value;
506}
507
35b8730d
JD
508location
509muscle_percent_define_get_loc (char const *variable)
510{
511 char const *loc_name;
10659d0e 512 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
35b8730d 513 if (!muscle_find_const (loc_name))
6fb8b256 514 complain (fatal, _("%s: undefined %%define variable %s"),
4a9cd8f2 515 "muscle_percent_define_get_loc", quote (variable));
c1cc91bd 516 return location_decode (loc_name);
35b8730d
JD
517}
518
519char const *
520muscle_percent_define_get_syncline (char const *variable)
521{
522 char const *syncline_name;
523 char const *syncline;
10659d0e
JD
524 syncline_name =
525 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
35b8730d
JD
526 syncline = muscle_find_const (syncline_name);
527 if (!syncline)
6fb8b256 528 complain (fatal, _("%s: undefined %%define variable %s"),
4a9cd8f2 529 "muscle_percent_define_get_syncline", quote (variable));
35b8730d
JD
530 return syncline;
531}
532
f124d423
JD
533bool
534muscle_percent_define_ifdef (char const *variable)
535{
536 char const *name;
537 char const *usage_name;
538 char const *value;
539
10659d0e
JD
540 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
541 usage_name =
542 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
f124d423
JD
543
544 value = muscle_find_const (name);
545 if (value)
546 {
547 muscle_insert (usage_name, "");
548 return true;
549 }
550
551 return false;
552}
553
9611cfa2
JD
554bool
555muscle_percent_define_flag_if (char const *variable)
556{
cbd50549 557 char const *invalid_boolean_name;
9611cfa2
JD
558 bool result = false;
559
10659d0e
JD
560 invalid_boolean_name =
561 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
9611cfa2 562
f124d423 563 if (muscle_percent_define_ifdef (variable))
9611cfa2 564 {
f124d423 565 char *value = muscle_percent_define_get (variable);
f518dbaf 566 if (value[0] == '\0' || STREQ (value, "true"))
9611cfa2 567 result = true;
f518dbaf 568 else if (STREQ (value, "false"))
9611cfa2 569 result = false;
cbd50549
JD
570 else if (!muscle_find_const (invalid_boolean_name))
571 {
572 muscle_insert (invalid_boolean_name, "");
6fb8b256
VS
573 location loc = muscle_percent_define_get_loc (variable);
574 complain_at (loc, complaint,
575 _("invalid value for %%define Boolean variable %s"),
576 quote (variable));
cbd50549 577 }
f124d423 578 free (value);
9611cfa2
JD
579 }
580 else
6fb8b256
VS
581 complain (fatal, _("%s: undefined %%define variable %s"),
582 "muscle_percent_define_flag", quote (variable));
9611cfa2 583
9611cfa2
JD
584 return result;
585}
586
587void
588muscle_percent_define_default (char const *variable, char const *value)
589{
590 char const *name;
591 char const *loc_name;
35b8730d 592 char const *syncline_name;
10659d0e
JD
593 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
594 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
595 syncline_name =
596 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
9611cfa2
JD
597 if (!muscle_find_const (name))
598 {
599 location loc;
600 MUSCLE_INSERT_STRING (name, value);
92822aff
JD
601 loc.start.file = loc.end.file = "<default value>";
602 loc.start.line = loc.end.line = -1;
603 loc.start.column = loc.end.column = -1;
9611cfa2
JD
604 muscle_insert (loc_name, "");
605 muscle_location_grow (loc_name, loc);
35b8730d 606 muscle_insert (syncline_name, "");
9611cfa2
JD
607 }
608}
609
f124d423 610void
b1a81613 611muscle_percent_define_check_values (char const * const *values)
f124d423 612{
b1a81613
JD
613 for (; *values; ++values)
614 {
f4909773 615 char const * const *variablep = values;
b1a81613 616 char const *name;
b1a81613
JD
617 char *value;
618
10659d0e 619 name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
b1a81613 620
c1cc91bd 621 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 {
631 location loc = muscle_percent_define_get_loc (*variablep);
6fb8b256
VS
632 complain_at (loc, complaint,
633 _("invalid value for %%define variable %s: %s"),
634 quote (*variablep), quote_n (1, value));
f4909773 635 for (values = variablep + 1; *values; ++values)
6fb8b256
VS
636 complain_at (loc, complaint, _("accepted value: %s"),
637 quote (*values));
f4909773
JD
638 }
639 else
640 {
641 while (*values)
642 ++values;
b1a81613 643 }
b1a81613
JD
644 free (value);
645 }
646 else
6fb8b256
VS
647 complain (fatal, _("%s: undefined %%define variable %s"),
648 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 649 }
f124d423
JD
650}
651
9611cfa2
JD
652void
653muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
654 char const *code, location code_loc)
655{
656 char const *name;
10659d0e 657 name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
658 muscle_code_grow (name, code, code_loc);
659 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
660 qualifier_loc);
661}
662
663
ae7453f2
AD
664/*------------------------------------------------.
665| Output the definition of ENTRY as a m4_define. |
666`------------------------------------------------*/
be2a1a68 667
e00b6826 668static inline bool
8322e8f5 669muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
670{
671 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 672 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
673 return true;
674}
675
676static bool
677muscle_m4_output_processor (void *entry, void *out)
678{
679 return muscle_m4_output (entry, out);
be2a1a68
AD
680}
681
682
ae7453f2
AD
683/*----------------------------------------------------------------.
684| Output the definition of all the current muscles into a list of |
685| m4_defines. |
686`----------------------------------------------------------------*/
be2a1a68
AD
687
688void
689muscles_m4_output (FILE *out)
690{
e00b6826 691 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 692}