]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
Merge remote-tracking branch 'origin/maint'
[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
14bfd2e9
AD
31muscle_kind
32muscle_kind_new (char const *k)
33{
34 if (STREQ (k, "code"))
35 return muscle_code;
36 else if (STREQ (k, "keyword"))
37 return muscle_keyword;
38 else if (STREQ (k, "string"))
39 return muscle_string;
40 aver (0);
41}
42
43char const *
44muscle_kind_string (muscle_kind k)
45{
46 switch (k)
47 {
48 case muscle_code: return "code";
49 case muscle_keyword: return "keyword";
50 case muscle_string: return "string";
51 }
52 aver (0);
53}
54
55
eb095650
PE
56/* A key-value pair, along with storage that can be reclaimed when
57 this pair is no longer needed. */
8322e8f5
PE
58typedef struct
59{
eb095650
PE
60 char const *key;
61 char const *value;
62 char *storage;
14bfd2e9 63 muscle_kind kind;
8322e8f5 64} muscle_entry;
592e8d4d
AD
65
66/* An obstack used to create some entries. */
67struct obstack muscle_obstack;
68
beda758b
AD
69/* Initial capacity of muscles hash table. */
70#define HT_INITIAL_CAPACITY 257
f753cd62 71
04098407 72static struct hash_table *muscle_table = NULL;
f753cd62 73
beda758b
AD
74static bool
75hash_compare_muscles (void const *x, void const *y)
f753cd62 76{
8322e8f5
PE
77 muscle_entry const *m1 = x;
78 muscle_entry const *m2 = y;
f518dbaf 79 return STREQ (m1->key, m2->key);
f753cd62
MA
80}
81
233a88ad
PE
82static size_t
83hash_muscle (const void *x, size_t tablesize)
f753cd62 84{
8322e8f5 85 muscle_entry const *m = x;
beda758b 86 return hash_string (m->key, tablesize);
f753cd62
MA
87}
88
c56d0037
AD
89/* Create a fresh muscle name KEY, and insert in the hash table. */
90static void *
91muscle_entry_new (char const *key)
92{
93 muscle_entry *res = xmalloc (sizeof *res);
94 res->key = key;
95 res->value = NULL;
96 res->storage = NULL;
97 if (!hash_insert (muscle_table, res))
98 xalloc_die ();
99 return res;
100}
101
eb095650
PE
102static void
103muscle_entry_free (void *entry)
104{
105 muscle_entry *mentry = entry;
106 free (mentry->storage);
107 free (mentry);
108}
109
f753cd62
MA
110void
111muscle_init (void)
112{
ae7453f2
AD
113 /* Initialize the muscle obstack. */
114 obstack_init (&muscle_obstack);
115
beda758b 116 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
e9690142 117 hash_compare_muscles, muscle_entry_free);
f753cd62
MA
118
119 /* Version and input file. */
ae7453f2 120 MUSCLE_INSERT_STRING ("version", VERSION);
f753cd62
MA
121}
122
592e8d4d 123
592e8d4d
AD
124void
125muscle_free (void)
126{
127 hash_free (muscle_table);
128 obstack_free (&muscle_obstack, NULL);
129}
130
c56d0037
AD
131/* Look for the muscle named KEY. Return NULL if does not exist. */
132static
133muscle_entry *
134muscle_lookup (char const *key)
f753cd62 135{
8322e8f5 136 muscle_entry probe;
ae7453f2 137 probe.key = key;
c56d0037
AD
138 return hash_lookup (muscle_table, &probe);
139}
beda758b 140
c56d0037
AD
141
142void
143muscle_insert (char const *key, char const *value)
144{
145 muscle_entry *entry = muscle_lookup (key);
146 if (entry)
4502eadc 147 free (entry->storage);
c56d0037
AD
148 else
149 /* First insertion in the hash. */
150 entry = muscle_entry_new (key);
beda758b 151 entry->value = value;
4502eadc 152 entry->storage = NULL;
f753cd62
MA
153}
154
ae7453f2
AD
155
156/*-------------------------------------------------------------------.
ff5150d9
PE
157| Append VALUE to the current value of KEY. If KEY did not already |
158| exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
159| associated value. Copy VALUE and SEPARATOR. |
ae7453f2
AD
160`-------------------------------------------------------------------*/
161
162void
163muscle_grow (const char *key, const char *val, const char *separator)
164{
c56d0037 165 muscle_entry *entry = muscle_lookup (key);
ae7453f2 166
c56d0037 167 if (entry)
ae7453f2
AD
168 {
169 /* Grow the current value. */
170 char *new_val;
6fbe73b6 171 obstack_printf (&muscle_obstack, "%s%s%s", entry->value, separator, val);
eb095650 172 free (entry->storage);
6fbe73b6 173 new_val = obstack_finish0 (&muscle_obstack);
eb095650 174 entry->value = entry->storage = xstrdup (new_val);
ae7453f2
AD
175 obstack_free (&muscle_obstack, new_val);
176 }
c56d0037
AD
177 else
178 {
179 /* First insertion in the hash. */
180 entry = muscle_entry_new (key);
181 entry->value = entry->storage = xstrdup (val);
182 }
ae7453f2
AD
183}
184
cd3684cf 185/*------------------------------------------------------------------.
35b8730d
JD
186| Using muscle_grow, append a synchronization line for the location |
187| LOC to the current value of KEY. |
cd3684cf
AD
188`------------------------------------------------------------------*/
189
35b8730d
JD
190static void
191muscle_syncline_grow (char const *key, location loc)
cd3684cf
AD
192{
193 char *extension = NULL;
aaf63e45 194 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
0601c3bf
AD
195 obstack_quote (&muscle_obstack,
196 quotearg_style (c_quoting_style, loc.start.file));
197 obstack_sgrow (&muscle_obstack, ")[");
6fbe73b6 198 extension = obstack_finish0 (&muscle_obstack);
cd3684cf 199 muscle_grow (key, extension, "");
eb095650 200 obstack_free (&muscle_obstack, extension);
cd3684cf
AD
201}
202
35b8730d
JD
203/*------------------------------------------------------------------.
204| Append VALUE to the current value of KEY, using muscle_grow. But |
205| in addition, issue a synchronization line for the location LOC |
206| using muscle_syncline_grow. |
207`------------------------------------------------------------------*/
208
209void
210muscle_code_grow (const char *key, const char *val, location loc)
211{
212 muscle_syncline_grow (key, loc);
213 muscle_grow (key, val, "\n");
214}
215
cd3684cf 216
c56d0037
AD
217void
218muscle_pair_list_grow (const char *muscle,
219 const char *a1, const char *a2)
ae7453f2 220{
66d30cd4 221 char *pair;
0601c3bf
AD
222 obstack_sgrow (&muscle_obstack, "[");
223 obstack_quote (&muscle_obstack, a1);
224 obstack_sgrow (&muscle_obstack, ", ");
225 obstack_quote (&muscle_obstack, a2);
226 obstack_sgrow (&muscle_obstack, "]");
6fbe73b6 227 pair = obstack_finish0 (&muscle_obstack);
66d30cd4
AD
228 muscle_grow (muscle, pair, ",\n");
229 obstack_free (&muscle_obstack, pair);
ae7453f2
AD
230}
231
7eb8a0bc 232
7eb8a0bc
JD
233char const *
234muscle_find_const (char const *key)
235{
c56d0037
AD
236 muscle_entry *entry = muscle_lookup (key);
237 return entry ? entry->value : NULL;
7eb8a0bc
JD
238}
239
240
ff5150d9 241char *
7eb8a0bc 242muscle_find (char const *key)
f753cd62 243{
c56d0037
AD
244 muscle_entry *entry = muscle_lookup (key);
245 if (entry)
4502eadc 246 {
c56d0037
AD
247 aver (entry->value == entry->storage);
248 return entry->storage;
4502eadc
JD
249 }
250 return NULL;
f753cd62 251}
be2a1a68
AD
252
253
45eebca4 254/* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
e5878229
AD
255 digraphs for special characters in the file name. */
256
257static void
9611cfa2
JD
258muscle_boundary_grow (char const *key, boundary bound)
259{
260 char *extension;
eea7239a 261 obstack_sgrow (&muscle_obstack, "[[");
13b712d7 262 obstack_escape (&muscle_obstack, bound.file);
6fbe73b6
AD
263 obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
264 extension = obstack_finish0 (&muscle_obstack);
9611cfa2
JD
265 muscle_grow (key, extension, "");
266 obstack_free (&muscle_obstack, extension);
267}
268
e5878229 269
45eebca4 270/* In the format '[[file_name:line.column]], [[file_name:line.column]]',
e5878229
AD
271 append LOC to MUSCLE. Use digraphs for special characters in each
272 file name. */
273
274static void
9611cfa2
JD
275muscle_location_grow (char const *key, location loc)
276{
9611cfa2 277 muscle_boundary_grow (key, loc.start);
eea7239a 278 muscle_grow (key, "", ", ");
9611cfa2 279 muscle_boundary_grow (key, loc.end);
9611cfa2
JD
280}
281
c1cc91bd 282#define COMMON_DECODE(Value) \
9b858541
AD
283 case '$': \
284 aver (*++(Value) == ']'); \
285 aver (*++(Value) == '['); \
286 obstack_sgrow (&muscle_obstack, "$"); \
287 break; \
288 case '@': \
289 switch (*++(Value)) \
290 { \
291 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
292 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
293 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
294 default: aver (false); break; \
295 } \
296 break; \
297 default: \
298 obstack_1grow (&muscle_obstack, *(Value)); \
f124d423
JD
299 break;
300
c1cc91bd 301/* Reverse of obstack_escape. */
f124d423 302static char *
c1cc91bd 303string_decode (char const *key)
f124d423 304{
1ad6f4da 305 char const *value = muscle_find_const (key);
f124d423
JD
306 char *value_decoded;
307 char *result;
308
f124d423
JD
309 if (!value)
310 return NULL;
311 do {
312 switch (*value)
313 {
c1cc91bd 314 COMMON_DECODE (value)
f124d423
JD
315 case '[':
316 case ']':
317 aver (false);
318 break;
319 }
320 } while (*value++);
321 value_decoded = obstack_finish (&muscle_obstack);
322 result = xstrdup (value_decoded);
323 obstack_free (&muscle_obstack, value_decoded);
324 return result;
325}
326
9611cfa2
JD
327/* Reverse of muscle_location_grow. */
328static location
c1cc91bd 329location_decode (char const *key)
9611cfa2
JD
330{
331 location loc;
332 char const *value = muscle_find_const (key);
333 aver (value);
334 aver (*value == '[');
335 aver (*++value == '[');
336 while (*++value)
337 switch (*value)
338 {
c1cc91bd 339 COMMON_DECODE (value)
9611cfa2
JD
340 case '[':
341 aver (false);
342 break;
343 case ']':
344 {
345 char *boundary_str;
346 aver (*++value == ']');
6fbe73b6 347 boundary_str = obstack_finish0 (&muscle_obstack);
9611cfa2
JD
348 switch (*++value)
349 {
350 case ',':
351 boundary_set_from_string (&loc.start, boundary_str);
352 obstack_free (&muscle_obstack, boundary_str);
353 aver (*++value == ' ');
354 aver (*++value == '[');
355 aver (*++value == '[');
356 break;
357 case '\0':
358 boundary_set_from_string (&loc.end, boundary_str);
359 obstack_free (&muscle_obstack, boundary_str);
360 return loc;
361 break;
362 default:
363 aver (false);
364 break;
365 }
366 }
367 break;
9611cfa2
JD
368 }
369 aver (false);
370 return loc;
371}
372
373void
374muscle_user_name_list_grow (char const *key, char const *user_name,
375 location loc)
376{
377 muscle_grow (key, "[[[[", ",");
378 muscle_grow (key, user_name, "");
379 muscle_grow (key, "]], ", "");
380 muscle_location_grow (key, loc);
381 muscle_grow (key, "]]", "");
382}
383
bc603897
AD
384
385/** Return an allocated string that represents the %define directive
386 that performs the assignment.
387
388 @param assignment "VAR", or "VAR=VAL".
389 @param value default value if VAL \a assignment has no '='.
390
391 For instance:
392 "foo", NULL => "%define foo"
393 "foo", "baz" => "%define foo baz"
394 "foo=bar", NULL => "%define foo bar"
395 "foo=bar", "baz" => "%define foo bar"
396 "foo=", NULL => "%define foo"
397 "foo=", "baz" => "%define foo"
398 */
399
53f8e409
AD
400static
401char *
402define_directive (char const *assignment, char const *value)
403{
bc603897
AD
404 char *eq = strchr (assignment, '=');
405 char const *fmt = !eq && value && *value ? "%%define %s %s" : "%%define %s";
53f8e409
AD
406 char *res = xmalloc (strlen (fmt) + strlen (assignment)
407 + (value ? strlen (value) : 0));
408 sprintf (res, fmt, assignment, value);
bc603897
AD
409 eq = strchr (res, '=');
410 if (eq)
411 *eq = eq[1] ? ' ' : '\0';
53f8e409
AD
412 return res;
413}
414
171ad99d 415/** If the \a variable name is obsolete, return the name to use,
bc603897
AD
416 * otherwise \a variable. If the \a value is obsolete, update it too.
417 *
418 * Allocates the returned value. */
171ad99d 419static
bc603897 420char *
53f8e409
AD
421muscle_percent_variable_update (char const *variable, location variable_loc,
422 char const **value)
171ad99d
AD
423{
424 typedef struct
425 {
426 const char *obsolete;
427 const char *updated;
428 } conversion_type;
429 const conversion_type conversion[] =
430 {
431 { "api.push_pull", "api.push-pull", },
2a6b66c5 432 { "api.tokens.prefix", "api.token.prefix", },
f9f1b3eb 433 { "lex_symbol", "api.token.constructor", },
db8ab2be 434 { "location_type", "api.location.type", },
f3bc3386
AD
435 { "lr.default-reductions", "lr.default-reduction", },
436 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", },
437 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", },
171ad99d 438 { "namespace", "api.namespace", },
4119d1ea 439 { "stype", "api.value.type", },
bc603897
AD
440 { "variant=", "api.value.type=variant", },
441 { "variant=true", "api.value.type=variant", },
53f8e409 442 { NULL, NULL, }
171ad99d 443 };
53f8e409
AD
444 conversion_type const *c;
445 for (c = conversion; c->obsolete; ++c)
bc603897
AD
446 {
447 char const *eq = strchr (c->obsolete, '=');
448 if (eq
449 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
450 && STREQ (eq + 1, *value))
451 : STREQ (c->obsolete, variable))
452 {
453 char *old = define_directive (c->obsolete, *value);
454 char *upd = define_directive (c->updated, *value);
455 deprecated_directive (&variable_loc, old, upd);
456 free (old);
457 free (upd);
458 char *res = xstrdup (c->updated);
459 {
460 char *eq2 = strchr (res, '=');
461 if (eq2)
462 {
463 *eq2 = '\0';
464 *value = eq2 + 1;
465 }
466 }
467 return res;
468 }
53f8e409 469 }
bc603897 470 return xstrdup (variable);
171ad99d
AD
471}
472
9611cfa2 473void
2aa5b259 474muscle_percent_define_insert (char const *var, location variable_loc,
14bfd2e9 475 muscle_kind kind,
de5ab940
JD
476 char const *value,
477 muscle_percent_define_how how)
9611cfa2 478{
2aa5b259 479 /* Backward compatibility. */
53f8e409 480 char *variable = muscle_percent_variable_update (var, variable_loc, &value);
2aa5b259
AD
481 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
482 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
483 char const *syncline_name =
10659d0e 484 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
2aa5b259 485 char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
14bfd2e9
AD
486 char const *kind_name =
487 UNIQSTR_CONCAT ("percent_define_kind(", 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);
14bfd2e9 513 MUSCLE_INSERT_STRING (kind_name, muscle_kind_string (kind));
bc603897
AD
514 end:
515 free (variable);
9611cfa2
JD
516}
517
4920ae8b
AD
518/* This is used for backward compatibility, e.g., "%define api.pure"
519 supersedes "%pure-parser". */
520void
521muscle_percent_define_ensure (char const *variable, location loc,
522 bool value)
523{
1ad6f4da 524 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
36a17b50 525 char const *val = value ? "" : "false";
4920ae8b 526
36a17b50
AD
527 /* Don't complain is VARIABLE is already defined, but be sure to set
528 its value to VAL. */
4920ae8b 529 if (!muscle_find_const (name))
14bfd2e9 530 muscle_percent_define_insert (variable, loc, muscle_keyword, val,
de5ab940 531 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b 532 if (muscle_percent_define_flag_if (variable) != value)
14bfd2e9 533 muscle_percent_define_insert (variable, loc, muscle_keyword, val,
de5ab940 534 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
535}
536
f124d423
JD
537char *
538muscle_percent_define_get (char const *variable)
539{
1ad6f4da
AD
540 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
541 char const *usage_name =
542 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
543 char *value = string_decode (name);
f124d423
JD
544 if (!value)
545 value = xstrdup ("");
1ad6f4da
AD
546
547 muscle_insert (usage_name, "");
f124d423
JD
548 return value;
549}
550
35b8730d
JD
551location
552muscle_percent_define_get_loc (char const *variable)
553{
1ad6f4da 554 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
35b8730d 555 if (!muscle_find_const (loc_name))
bb8e56ff 556 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 557 "muscle_percent_define_get_loc", quote (variable));
c1cc91bd 558 return location_decode (loc_name);
35b8730d
JD
559}
560
561char const *
562muscle_percent_define_get_syncline (char const *variable)
563{
1ad6f4da 564 char const *syncline_name =
10659d0e 565 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
1ad6f4da 566 char const *syncline = muscle_find_const (syncline_name);
35b8730d 567 if (!syncline)
bb8e56ff 568 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 569 "muscle_percent_define_get_syncline", quote (variable));
35b8730d
JD
570 return syncline;
571}
572
f124d423
JD
573bool
574muscle_percent_define_ifdef (char const *variable)
575{
1ad6f4da
AD
576 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
577 char const *usage_name =
10659d0e 578 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
1ad6f4da 579 char const *value = muscle_find_const (name);
f124d423
JD
580 if (value)
581 {
582 muscle_insert (usage_name, "");
583 return true;
584 }
585
586 return false;
587}
588
9611cfa2
JD
589bool
590muscle_percent_define_flag_if (char const *variable)
591{
1ad6f4da 592 char const *invalid_boolean_name =
10659d0e 593 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
1ad6f4da 594 bool result = false;
9611cfa2 595
f124d423 596 if (muscle_percent_define_ifdef (variable))
9611cfa2 597 {
f124d423 598 char *value = muscle_percent_define_get (variable);
f518dbaf 599 if (value[0] == '\0' || STREQ (value, "true"))
9611cfa2 600 result = true;
f518dbaf 601 else if (STREQ (value, "false"))
9611cfa2 602 result = false;
cbd50549
JD
603 else if (!muscle_find_const (invalid_boolean_name))
604 {
605 muscle_insert (invalid_boolean_name, "");
6fb8b256 606 location loc = muscle_percent_define_get_loc (variable);
bb8e56ff
TR
607 complain (&loc, complaint,
608 _("invalid value for %%define Boolean variable %s"),
609 quote (variable));
cbd50549 610 }
f124d423 611 free (value);
9611cfa2
JD
612 }
613 else
bb8e56ff 614 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 615 "muscle_percent_define_flag", quote (variable));
9611cfa2 616
9611cfa2
JD
617 return result;
618}
619
620void
621muscle_percent_define_default (char const *variable, char const *value)
622{
1ad6f4da
AD
623 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
624 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
625 char const *syncline_name =
10659d0e 626 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
9611cfa2
JD
627 if (!muscle_find_const (name))
628 {
629 location loc;
630 MUSCLE_INSERT_STRING (name, value);
92822aff
JD
631 loc.start.file = loc.end.file = "<default value>";
632 loc.start.line = loc.end.line = -1;
633 loc.start.column = loc.end.column = -1;
9611cfa2
JD
634 muscle_insert (loc_name, "");
635 muscle_location_grow (loc_name, loc);
35b8730d 636 muscle_insert (syncline_name, "");
9611cfa2
JD
637 }
638}
639
f124d423 640void
b1a81613 641muscle_percent_define_check_values (char const * const *values)
f124d423 642{
b1a81613
JD
643 for (; *values; ++values)
644 {
f4909773 645 char const * const *variablep = values;
1ad6f4da
AD
646 char const *name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
647 char *value = string_decode (name);
b1a81613
JD
648 if (value)
649 {
b1a81613
JD
650 for (++values; *values; ++values)
651 {
f518dbaf 652 if (STREQ (value, *values))
f4909773
JD
653 break;
654 }
655 if (!*values)
656 {
a974c1ec 657 unsigned i = 0;
f4909773 658 location loc = muscle_percent_define_get_loc (*variablep);
b999409e
TR
659 complain_indent (&loc, complaint, &i,
660 _("invalid value for %%define variable %s: %s"),
661 quote (*variablep), quote_n (1, value));
a974c1ec 662 i += SUB_INDENT;
f4909773 663 for (values = variablep + 1; *values; ++values)
219458e2 664 complain_indent (&loc, complaint | no_caret | silent, &i,
ea9e670d 665 _("accepted value: %s"), quote (*values));
f4909773
JD
666 }
667 else
668 {
669 while (*values)
670 ++values;
b1a81613 671 }
b1a81613
JD
672 free (value);
673 }
674 else
bb8e56ff 675 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 676 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 677 }
f124d423
JD
678}
679
9611cfa2
JD
680void
681muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
682 char const *code, location code_loc)
683{
1ad6f4da 684 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
685 muscle_code_grow (name, code, code_loc);
686 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
687 qualifier_loc);
688}
689
690
ae7453f2
AD
691/*------------------------------------------------.
692| Output the definition of ENTRY as a m4_define. |
693`------------------------------------------------*/
be2a1a68 694
e00b6826 695static inline bool
8322e8f5 696muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68 697{
1ad6f4da
AD
698 fprintf (out,
699 "m4_define([b4_%s],\n"
700 "[[%s]])\n\n\n", entry->key, entry->value);
e00b6826
PE
701 return true;
702}
703
704static bool
705muscle_m4_output_processor (void *entry, void *out)
706{
707 return muscle_m4_output (entry, out);
be2a1a68
AD
708}
709
710
be2a1a68
AD
711void
712muscles_m4_output (FILE *out)
713{
e00b6826 714 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 715}