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