]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
grammar: warn about unused precedence for symbols
[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
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;
6fbe73b6 160 obstack_printf (&muscle_obstack, "%s%s%s", entry->value, separator, val);
eb095650 161 free (entry->storage);
6fbe73b6 162 new_val = obstack_finish0 (&muscle_obstack);
eb095650 163 entry->value = entry->storage = xstrdup (new_val);
ae7453f2
AD
164 obstack_free (&muscle_obstack, new_val);
165 }
166}
167
cd3684cf 168/*------------------------------------------------------------------.
35b8730d
JD
169| Using muscle_grow, append a synchronization line for the location |
170| LOC to the current value of KEY. |
cd3684cf
AD
171`------------------------------------------------------------------*/
172
35b8730d
JD
173static void
174muscle_syncline_grow (char const *key, location loc)
cd3684cf
AD
175{
176 char *extension = NULL;
aaf63e45 177 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
0601c3bf
AD
178 obstack_quote (&muscle_obstack,
179 quotearg_style (c_quoting_style, loc.start.file));
180 obstack_sgrow (&muscle_obstack, ")[");
6fbe73b6 181 extension = obstack_finish0 (&muscle_obstack);
cd3684cf 182 muscle_grow (key, extension, "");
eb095650 183 obstack_free (&muscle_obstack, extension);
cd3684cf
AD
184}
185
35b8730d
JD
186/*------------------------------------------------------------------.
187| Append VALUE to the current value of KEY, using muscle_grow. But |
188| in addition, issue a synchronization line for the location LOC |
189| using muscle_syncline_grow. |
190`------------------------------------------------------------------*/
191
192void
193muscle_code_grow (const char *key, const char *val, location loc)
194{
195 muscle_syncline_grow (key, loc);
196 muscle_grow (key, val, "\n");
197}
198
cd3684cf 199
ae7453f2 200void muscle_pair_list_grow (const char *muscle,
e9690142 201 const char *a1, const char *a2)
ae7453f2 202{
66d30cd4 203 char *pair;
0601c3bf
AD
204 obstack_sgrow (&muscle_obstack, "[");
205 obstack_quote (&muscle_obstack, a1);
206 obstack_sgrow (&muscle_obstack, ", ");
207 obstack_quote (&muscle_obstack, a2);
208 obstack_sgrow (&muscle_obstack, "]");
6fbe73b6 209 pair = obstack_finish0 (&muscle_obstack);
66d30cd4
AD
210 muscle_grow (muscle, pair, ",\n");
211 obstack_free (&muscle_obstack, pair);
ae7453f2
AD
212}
213
7eb8a0bc
JD
214
215/*----------------------------------------------------------------------------.
216| Find the value of muscle KEY. Unlike MUSCLE_FIND, this is always reliable |
217| to determine whether KEY has a value. |
218`----------------------------------------------------------------------------*/
219
220char const *
221muscle_find_const (char const *key)
222{
223 muscle_entry probe;
224 muscle_entry *result = NULL;
225
226 probe.key = key;
227 result = hash_lookup (muscle_table, &probe);
228 if (result)
229 return result->value;
230 return NULL;
231}
232
233
4502eadc
JD
234/*----------------------------------------------------------------------------.
235| Find the value of muscle KEY. Abort if muscle_insert was invoked more |
236| recently than muscle_grow for KEY since muscle_find can't return a |
237| char const *. |
238`----------------------------------------------------------------------------*/
ae7453f2 239
ff5150d9 240char *
7eb8a0bc 241muscle_find (char const *key)
f753cd62 242{
8322e8f5
PE
243 muscle_entry probe;
244 muscle_entry *result = NULL;
e9bca3ad 245
ae7453f2
AD
246 probe.key = key;
247 result = hash_lookup (muscle_table, &probe);
4502eadc
JD
248 if (result)
249 {
250 aver (result->value == result->storage);
251 return result->storage;
252 }
253 return NULL;
f753cd62 254}
be2a1a68
AD
255
256
e5878229
AD
257/* In the format `file_name:line.column', append BOUND to MUSCLE. Use
258 digraphs for special characters in the file name. */
259
260static void
9611cfa2
JD
261muscle_boundary_grow (char const *key, boundary bound)
262{
263 char *extension;
eea7239a 264 obstack_sgrow (&muscle_obstack, "[[");
13b712d7 265 obstack_escape (&muscle_obstack, bound.file);
6fbe73b6
AD
266 obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
267 extension = obstack_finish0 (&muscle_obstack);
9611cfa2
JD
268 muscle_grow (key, extension, "");
269 obstack_free (&muscle_obstack, extension);
270}
271
e5878229
AD
272
273/* In the format `[[file_name:line.column]], [[file_name:line.column]]',
274 append LOC to MUSCLE. Use digraphs for special characters in each
275 file name. */
276
277static void
9611cfa2
JD
278muscle_location_grow (char const *key, location loc)
279{
9611cfa2 280 muscle_boundary_grow (key, loc.start);
eea7239a 281 muscle_grow (key, "", ", ");
9611cfa2 282 muscle_boundary_grow (key, loc.end);
9611cfa2
JD
283}
284
c1cc91bd 285#define COMMON_DECODE(Value) \
9b858541
AD
286 case '$': \
287 aver (*++(Value) == ']'); \
288 aver (*++(Value) == '['); \
289 obstack_sgrow (&muscle_obstack, "$"); \
290 break; \
291 case '@': \
292 switch (*++(Value)) \
293 { \
294 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
295 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
296 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
297 default: aver (false); break; \
298 } \
299 break; \
300 default: \
301 obstack_1grow (&muscle_obstack, *(Value)); \
f124d423
JD
302 break;
303
c1cc91bd 304/* Reverse of obstack_escape. */
f124d423 305static char *
c1cc91bd 306string_decode (char const *key)
f124d423 307{
1ad6f4da 308 char const *value = muscle_find_const (key);
f124d423
JD
309 char *value_decoded;
310 char *result;
311
f124d423
JD
312 if (!value)
313 return NULL;
314 do {
315 switch (*value)
316 {
c1cc91bd 317 COMMON_DECODE (value)
f124d423
JD
318 case '[':
319 case ']':
320 aver (false);
321 break;
322 }
323 } while (*value++);
324 value_decoded = obstack_finish (&muscle_obstack);
325 result = xstrdup (value_decoded);
326 obstack_free (&muscle_obstack, value_decoded);
327 return result;
328}
329
9611cfa2
JD
330/* Reverse of muscle_location_grow. */
331static location
c1cc91bd 332location_decode (char const *key)
9611cfa2
JD
333{
334 location loc;
335 char const *value = muscle_find_const (key);
336 aver (value);
337 aver (*value == '[');
338 aver (*++value == '[');
339 while (*++value)
340 switch (*value)
341 {
c1cc91bd 342 COMMON_DECODE (value)
9611cfa2
JD
343 case '[':
344 aver (false);
345 break;
346 case ']':
347 {
348 char *boundary_str;
349 aver (*++value == ']');
6fbe73b6 350 boundary_str = obstack_finish0 (&muscle_obstack);
9611cfa2
JD
351 switch (*++value)
352 {
353 case ',':
354 boundary_set_from_string (&loc.start, boundary_str);
355 obstack_free (&muscle_obstack, boundary_str);
356 aver (*++value == ' ');
357 aver (*++value == '[');
358 aver (*++value == '[');
359 break;
360 case '\0':
361 boundary_set_from_string (&loc.end, boundary_str);
362 obstack_free (&muscle_obstack, boundary_str);
363 return loc;
364 break;
365 default:
366 aver (false);
367 break;
368 }
369 }
370 break;
9611cfa2
JD
371 }
372 aver (false);
373 return loc;
374}
375
376void
377muscle_user_name_list_grow (char const *key, char const *user_name,
378 location loc)
379{
380 muscle_grow (key, "[[[[", ",");
381 muscle_grow (key, user_name, "");
382 muscle_grow (key, "]], ", "");
383 muscle_location_grow (key, loc);
384 muscle_grow (key, "]]", "");
385}
386
bc603897
AD
387
388/** Return an allocated string that represents the %define directive
389 that performs the assignment.
390
391 @param assignment "VAR", or "VAR=VAL".
392 @param value default value if VAL \a assignment has no '='.
393
394 For instance:
395 "foo", NULL => "%define foo"
396 "foo", "baz" => "%define foo baz"
397 "foo=bar", NULL => "%define foo bar"
398 "foo=bar", "baz" => "%define foo bar"
399 "foo=", NULL => "%define foo"
400 "foo=", "baz" => "%define foo"
401 */
402
53f8e409
AD
403static
404char *
405define_directive (char const *assignment, char const *value)
406{
bc603897
AD
407 char *eq = strchr (assignment, '=');
408 char const *fmt = !eq && value && *value ? "%%define %s %s" : "%%define %s";
53f8e409
AD
409 char *res = xmalloc (strlen (fmt) + strlen (assignment)
410 + (value ? strlen (value) : 0));
411 sprintf (res, fmt, assignment, value);
bc603897
AD
412 eq = strchr (res, '=');
413 if (eq)
414 *eq = eq[1] ? ' ' : '\0';
53f8e409
AD
415 return res;
416}
417
171ad99d 418/** If the \a variable name is obsolete, return the name to use,
bc603897
AD
419 * otherwise \a variable. If the \a value is obsolete, update it too.
420 *
421 * Allocates the returned value. */
171ad99d 422static
bc603897 423char *
53f8e409
AD
424muscle_percent_variable_update (char const *variable, location variable_loc,
425 char const **value)
171ad99d
AD
426{
427 typedef struct
428 {
429 const char *obsolete;
430 const char *updated;
431 } conversion_type;
432 const conversion_type conversion[] =
433 {
434 { "api.push_pull", "api.push-pull", },
2a6b66c5 435 { "api.tokens.prefix", "api.token.prefix", },
f9f1b3eb 436 { "lex_symbol", "api.token.constructor", },
db8ab2be 437 { "location_type", "api.location.type", },
f3bc3386
AD
438 { "lr.default-reductions", "lr.default-reduction", },
439 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", },
440 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", },
171ad99d 441 { "namespace", "api.namespace", },
4119d1ea 442 { "stype", "api.value.type", },
bc603897
AD
443 { "variant=", "api.value.type=variant", },
444 { "variant=true", "api.value.type=variant", },
53f8e409 445 { NULL, NULL, }
171ad99d 446 };
53f8e409
AD
447 conversion_type const *c;
448 for (c = conversion; c->obsolete; ++c)
bc603897
AD
449 {
450 char const *eq = strchr (c->obsolete, '=');
451 if (eq
452 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
453 && STREQ (eq + 1, *value))
454 : STREQ (c->obsolete, variable))
455 {
456 char *old = define_directive (c->obsolete, *value);
457 char *upd = define_directive (c->updated, *value);
458 deprecated_directive (&variable_loc, old, upd);
459 free (old);
460 free (upd);
461 char *res = xstrdup (c->updated);
462 {
463 char *eq2 = strchr (res, '=');
464 if (eq2)
465 {
466 *eq2 = '\0';
467 *value = eq2 + 1;
468 }
469 }
470 return res;
471 }
53f8e409 472 }
bc603897 473 return xstrdup (variable);
171ad99d
AD
474}
475
9611cfa2 476void
2aa5b259 477muscle_percent_define_insert (char const *var, location variable_loc,
de5ab940
JD
478 char const *value,
479 muscle_percent_define_how how)
9611cfa2 480{
2aa5b259 481 /* Backward compatibility. */
53f8e409 482 char *variable = muscle_percent_variable_update (var, variable_loc, &value);
2aa5b259
AD
483 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
484 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
485 char const *syncline_name =
10659d0e 486 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
2aa5b259 487 char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
9611cfa2 488
de5ab940
JD
489 /* Command-line options are processed before the grammar file. */
490 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
491 && muscle_find_const (name))
9611cfa2 492 {
1ad6f4da 493 muscle_percent_define_how how_old = atoi (muscle_find_const (how_name));
6b1e1872 494 unsigned i = 0;
de5ab940 495 if (how_old == MUSCLE_PERCENT_DEFINE_F)
bc603897 496 goto end;
b999409e
TR
497 complain_indent (&variable_loc, complaint, &i,
498 _("%%define variable %s redefined"),
499 quote (variable));
6b1e1872 500 i += SUB_INDENT;
b999409e
TR
501 location loc = muscle_percent_define_get_loc (variable);
502 complain_indent (&loc, complaint, &i, _("previous definition"));
9611cfa2 503 }
9611cfa2 504
de5ab940 505 MUSCLE_INSERT_STRING (name, value);
9611cfa2
JD
506 muscle_insert (loc_name, "");
507 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
508 muscle_insert (syncline_name, "");
509 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
510 muscle_user_name_list_grow ("percent_define_user_variables", variable,
511 variable_loc);
de5ab940 512 MUSCLE_INSERT_INT (how_name, how);
bc603897
AD
513 end:
514 free (variable);
9611cfa2
JD
515}
516
4920ae8b
AD
517/* This is used for backward compatibility, e.g., "%define api.pure"
518 supersedes "%pure-parser". */
519void
520muscle_percent_define_ensure (char const *variable, location loc,
521 bool value)
522{
523 char const *val = value ? "" : "false";
1ad6f4da 524 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
4920ae8b
AD
525
526 /* %pure-parser is deprecated in favor of `%define api.pure', so use
527 `%define api.pure' in a backward-compatible manner here. First,
528 don't complain if %pure-parser is specified multiple times. */
529 if (!muscle_find_const (name))
de5ab940
JD
530 muscle_percent_define_insert (variable, loc, val,
531 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
532 /* In all cases, use api.pure now so that the backend doesn't complain if
533 the skeleton ignores api.pure, but do warn now if there's a previous
534 conflicting definition from an actual %define. */
535 if (muscle_percent_define_flag_if (variable) != value)
de5ab940
JD
536 muscle_percent_define_insert (variable, loc, val,
537 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
538}
539
f124d423
JD
540char *
541muscle_percent_define_get (char const *variable)
542{
1ad6f4da
AD
543 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
544 char const *usage_name =
545 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
546 char *value = string_decode (name);
f124d423
JD
547 if (!value)
548 value = xstrdup ("");
1ad6f4da
AD
549
550 muscle_insert (usage_name, "");
f124d423
JD
551 return value;
552}
553
35b8730d
JD
554location
555muscle_percent_define_get_loc (char const *variable)
556{
1ad6f4da 557 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
35b8730d 558 if (!muscle_find_const (loc_name))
bb8e56ff 559 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 560 "muscle_percent_define_get_loc", quote (variable));
c1cc91bd 561 return location_decode (loc_name);
35b8730d
JD
562}
563
564char const *
565muscle_percent_define_get_syncline (char const *variable)
566{
1ad6f4da 567 char const *syncline_name =
10659d0e 568 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
1ad6f4da 569 char const *syncline = muscle_find_const (syncline_name);
35b8730d 570 if (!syncline)
bb8e56ff 571 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 572 "muscle_percent_define_get_syncline", quote (variable));
35b8730d
JD
573 return syncline;
574}
575
f124d423
JD
576bool
577muscle_percent_define_ifdef (char const *variable)
578{
1ad6f4da
AD
579 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
580 char const *usage_name =
10659d0e 581 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
1ad6f4da 582 char const *value = muscle_find_const (name);
f124d423
JD
583 if (value)
584 {
585 muscle_insert (usage_name, "");
586 return true;
587 }
588
589 return false;
590}
591
9611cfa2
JD
592bool
593muscle_percent_define_flag_if (char const *variable)
594{
1ad6f4da 595 char const *invalid_boolean_name =
10659d0e 596 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
1ad6f4da 597 bool result = false;
9611cfa2 598
f124d423 599 if (muscle_percent_define_ifdef (variable))
9611cfa2 600 {
f124d423 601 char *value = muscle_percent_define_get (variable);
f518dbaf 602 if (value[0] == '\0' || STREQ (value, "true"))
9611cfa2 603 result = true;
f518dbaf 604 else if (STREQ (value, "false"))
9611cfa2 605 result = false;
cbd50549
JD
606 else if (!muscle_find_const (invalid_boolean_name))
607 {
608 muscle_insert (invalid_boolean_name, "");
6fb8b256 609 location loc = muscle_percent_define_get_loc (variable);
bb8e56ff
TR
610 complain (&loc, complaint,
611 _("invalid value for %%define Boolean variable %s"),
612 quote (variable));
cbd50549 613 }
f124d423 614 free (value);
9611cfa2
JD
615 }
616 else
bb8e56ff 617 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 618 "muscle_percent_define_flag", quote (variable));
9611cfa2 619
9611cfa2
JD
620 return result;
621}
622
623void
624muscle_percent_define_default (char const *variable, char const *value)
625{
1ad6f4da
AD
626 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
627 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
628 char const *syncline_name =
10659d0e 629 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
9611cfa2
JD
630 if (!muscle_find_const (name))
631 {
632 location loc;
633 MUSCLE_INSERT_STRING (name, value);
92822aff
JD
634 loc.start.file = loc.end.file = "<default value>";
635 loc.start.line = loc.end.line = -1;
636 loc.start.column = loc.end.column = -1;
9611cfa2
JD
637 muscle_insert (loc_name, "");
638 muscle_location_grow (loc_name, loc);
35b8730d 639 muscle_insert (syncline_name, "");
9611cfa2
JD
640 }
641}
642
f124d423 643void
b1a81613 644muscle_percent_define_check_values (char const * const *values)
f124d423 645{
b1a81613
JD
646 for (; *values; ++values)
647 {
f4909773 648 char const * const *variablep = values;
1ad6f4da
AD
649 char const *name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
650 char *value = string_decode (name);
b1a81613
JD
651 if (value)
652 {
b1a81613
JD
653 for (++values; *values; ++values)
654 {
f518dbaf 655 if (STREQ (value, *values))
f4909773
JD
656 break;
657 }
658 if (!*values)
659 {
a974c1ec 660 unsigned i = 0;
f4909773 661 location loc = muscle_percent_define_get_loc (*variablep);
b999409e
TR
662 complain_indent (&loc, complaint, &i,
663 _("invalid value for %%define variable %s: %s"),
664 quote (*variablep), quote_n (1, value));
a974c1ec 665 i += SUB_INDENT;
f4909773 666 for (values = variablep + 1; *values; ++values)
ea9e670d
AD
667 complain_indent (&loc, complaint | no_caret, &i,
668 _("accepted value: %s"), quote (*values));
f4909773
JD
669 }
670 else
671 {
672 while (*values)
673 ++values;
b1a81613 674 }
b1a81613
JD
675 free (value);
676 }
677 else
bb8e56ff 678 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 679 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 680 }
f124d423
JD
681}
682
9611cfa2
JD
683void
684muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
685 char const *code, location code_loc)
686{
1ad6f4da 687 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
688 muscle_code_grow (name, code, code_loc);
689 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
690 qualifier_loc);
691}
692
693
ae7453f2
AD
694/*------------------------------------------------.
695| Output the definition of ENTRY as a m4_define. |
696`------------------------------------------------*/
be2a1a68 697
e00b6826 698static inline bool
8322e8f5 699muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68 700{
1ad6f4da
AD
701 fprintf (out,
702 "m4_define([b4_%s],\n"
703 "[[%s]])\n\n\n", entry->key, entry->value);
e00b6826
PE
704 return true;
705}
706
707static bool
708muscle_m4_output_processor (void *entry, void *out)
709{
710 return muscle_m4_output (entry, out);
be2a1a68
AD
711}
712
713
ae7453f2
AD
714/*----------------------------------------------------------------.
715| Output the definition of all the current muscles into a list of |
716| m4_defines. |
717`----------------------------------------------------------------*/
be2a1a68
AD
718
719void
720muscles_m4_output (FILE *out)
721{
e00b6826 722 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 723}