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