]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
parsers: rename YY_NULL as YY_NULLPTR to avoid conflicts with Flex
[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 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
AD
301 case '$': \
302 aver (*++(Value) == ']'); \
303 aver (*++(Value) == '['); \
304 obstack_sgrow (&muscle_obstack, "$"); \
305 break; \
306 case '@': \
307 switch (*++(Value)) \
308 { \
309 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
310 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
311 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
312 default: aver (false); break; \
313 } \
314 break; \
315 default: \
316 obstack_1grow (&muscle_obstack, *(Value)); \
f124d423
JD
317 break;
318
c1cc91bd 319/* Reverse of obstack_escape. */
f124d423 320static char *
c1cc91bd 321string_decode (char const *key)
f124d423 322{
1ad6f4da 323 char const *value = muscle_find_const (key);
f124d423
JD
324 char *value_decoded;
325 char *result;
326
f124d423
JD
327 if (!value)
328 return NULL;
329 do {
330 switch (*value)
331 {
c1cc91bd 332 COMMON_DECODE (value)
f124d423
JD
333 case '[':
334 case ']':
335 aver (false);
336 break;
337 }
338 } while (*value++);
339 value_decoded = obstack_finish (&muscle_obstack);
340 result = xstrdup (value_decoded);
341 obstack_free (&muscle_obstack, value_decoded);
342 return result;
343}
344
9611cfa2
JD
345/* Reverse of muscle_location_grow. */
346static location
d9cfa2be 347location_decode (char const *value)
9611cfa2
JD
348{
349 location loc;
9611cfa2
JD
350 aver (value);
351 aver (*value == '[');
352 aver (*++value == '[');
353 while (*++value)
354 switch (*value)
355 {
c1cc91bd 356 COMMON_DECODE (value)
9611cfa2
JD
357 case '[':
358 aver (false);
359 break;
360 case ']':
361 {
362 char *boundary_str;
363 aver (*++value == ']');
6fbe73b6 364 boundary_str = obstack_finish0 (&muscle_obstack);
9611cfa2
JD
365 switch (*++value)
366 {
367 case ',':
368 boundary_set_from_string (&loc.start, boundary_str);
369 obstack_free (&muscle_obstack, boundary_str);
370 aver (*++value == ' ');
371 aver (*++value == '[');
372 aver (*++value == '[');
373 break;
374 case '\0':
375 boundary_set_from_string (&loc.end, boundary_str);
376 obstack_free (&muscle_obstack, boundary_str);
377 return loc;
378 break;
379 default:
380 aver (false);
381 break;
382 }
383 }
384 break;
9611cfa2
JD
385 }
386 aver (false);
387 return loc;
388}
389
390void
391muscle_user_name_list_grow (char const *key, char const *user_name,
392 location loc)
393{
08cc1a3b
AD
394 muscle_grow (key, "[[[[", ",", "");
395 muscle_grow (key, user_name, "", "");
396 muscle_grow (key, "]], ", "", "");
9611cfa2 397 muscle_location_grow (key, loc);
08cc1a3b 398 muscle_grow (key, "]]", "", "");
9611cfa2
JD
399}
400
bc603897
AD
401
402/** Return an allocated string that represents the %define directive
403 that performs the assignment.
404
405 @param assignment "VAR", or "VAR=VAL".
406 @param value default value if VAL \a assignment has no '='.
407
408 For instance:
409 "foo", NULL => "%define foo"
410 "foo", "baz" => "%define foo baz"
411 "foo=bar", NULL => "%define foo bar"
412 "foo=bar", "baz" => "%define foo bar"
413 "foo=", NULL => "%define foo"
414 "foo=", "baz" => "%define foo"
415 */
416
53f8e409
AD
417static
418char *
419define_directive (char const *assignment, char const *value)
420{
bc603897
AD
421 char *eq = strchr (assignment, '=');
422 char const *fmt = !eq && value && *value ? "%%define %s %s" : "%%define %s";
53f8e409
AD
423 char *res = xmalloc (strlen (fmt) + strlen (assignment)
424 + (value ? strlen (value) : 0));
425 sprintf (res, fmt, assignment, value);
bc603897
AD
426 eq = strchr (res, '=');
427 if (eq)
428 *eq = eq[1] ? ' ' : '\0';
53f8e409
AD
429 return res;
430}
431
171ad99d 432/** If the \a variable name is obsolete, return the name to use,
bc603897
AD
433 * otherwise \a variable. If the \a value is obsolete, update it too.
434 *
435 * Allocates the returned value. */
171ad99d 436static
bc603897 437char *
53f8e409
AD
438muscle_percent_variable_update (char const *variable, location variable_loc,
439 char const **value)
171ad99d
AD
440{
441 typedef struct
442 {
443 const char *obsolete;
444 const char *updated;
445 } conversion_type;
446 const conversion_type conversion[] =
447 {
448 { "api.push_pull", "api.push-pull", },
2a6b66c5 449 { "api.tokens.prefix", "api.token.prefix", },
f9f1b3eb 450 { "lex_symbol", "api.token.constructor", },
db8ab2be 451 { "location_type", "api.location.type", },
f3bc3386
AD
452 { "lr.default-reductions", "lr.default-reduction", },
453 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", },
454 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", },
171ad99d 455 { "namespace", "api.namespace", },
4119d1ea 456 { "stype", "api.value.type", },
bc603897
AD
457 { "variant=", "api.value.type=variant", },
458 { "variant=true", "api.value.type=variant", },
53f8e409 459 { NULL, NULL, }
171ad99d 460 };
53f8e409
AD
461 conversion_type const *c;
462 for (c = conversion; c->obsolete; ++c)
bc603897
AD
463 {
464 char const *eq = strchr (c->obsolete, '=');
465 if (eq
466 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
467 && STREQ (eq + 1, *value))
468 : STREQ (c->obsolete, variable))
469 {
470 char *old = define_directive (c->obsolete, *value);
471 char *upd = define_directive (c->updated, *value);
472 deprecated_directive (&variable_loc, old, upd);
473 free (old);
474 free (upd);
475 char *res = xstrdup (c->updated);
476 {
477 char *eq2 = strchr (res, '=');
478 if (eq2)
479 {
480 *eq2 = '\0';
481 *value = eq2 + 1;
482 }
483 }
484 return res;
485 }
53f8e409 486 }
bc603897 487 return xstrdup (variable);
171ad99d
AD
488}
489
9611cfa2 490void
2aa5b259 491muscle_percent_define_insert (char const *var, location variable_loc,
14bfd2e9 492 muscle_kind kind,
de5ab940
JD
493 char const *value,
494 muscle_percent_define_how how)
9611cfa2 495{
2aa5b259 496 /* Backward compatibility. */
53f8e409 497 char *variable = muscle_percent_variable_update (var, variable_loc, &value);
c98b5143
AD
498 uniqstr name = muscle_name (variable, NULL);
499 uniqstr loc_name = muscle_name (variable, "loc");
500 uniqstr syncline_name = muscle_name (variable, "syncline");
501 uniqstr how_name = muscle_name (variable, "how");
502 uniqstr kind_name = muscle_name (variable, "kind");
9611cfa2 503
de5ab940
JD
504 /* Command-line options are processed before the grammar file. */
505 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
506 && muscle_find_const (name))
9611cfa2 507 {
1ad6f4da 508 muscle_percent_define_how how_old = atoi (muscle_find_const (how_name));
6b1e1872 509 unsigned i = 0;
de5ab940 510 if (how_old == MUSCLE_PERCENT_DEFINE_F)
bc603897 511 goto end;
b999409e
TR
512 complain_indent (&variable_loc, complaint, &i,
513 _("%%define variable %s redefined"),
514 quote (variable));
6b1e1872 515 i += SUB_INDENT;
b999409e
TR
516 location loc = muscle_percent_define_get_loc (variable);
517 complain_indent (&loc, complaint, &i, _("previous definition"));
9611cfa2 518 }
9611cfa2 519
de5ab940 520 MUSCLE_INSERT_STRING (name, value);
9611cfa2
JD
521 muscle_insert (loc_name, "");
522 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
523 muscle_insert (syncline_name, "");
524 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
525 muscle_user_name_list_grow ("percent_define_user_variables", variable,
526 variable_loc);
de5ab940 527 MUSCLE_INSERT_INT (how_name, how);
14bfd2e9 528 MUSCLE_INSERT_STRING (kind_name, muscle_kind_string (kind));
bc603897
AD
529 end:
530 free (variable);
9611cfa2
JD
531}
532
4920ae8b
AD
533/* This is used for backward compatibility, e.g., "%define api.pure"
534 supersedes "%pure-parser". */
535void
536muscle_percent_define_ensure (char const *variable, location loc,
537 bool value)
538{
c98b5143 539 uniqstr name = muscle_name (variable, NULL);
36a17b50 540 char const *val = value ? "" : "false";
4920ae8b 541
36a17b50
AD
542 /* Don't complain is VARIABLE is already defined, but be sure to set
543 its value to VAL. */
bb4b189b
AD
544 if (!muscle_find_const (name)
545 || muscle_percent_define_flag_if (variable) != value)
14bfd2e9 546 muscle_percent_define_insert (variable, loc, muscle_keyword, val,
de5ab940 547 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
548}
549
0f9583b6
AD
550/* Mark %define VARIABLE as used. */
551static void
552muscle_percent_define_use (char const *variable)
553{
554 muscle_insert (muscle_name (variable, "bison_variables"), "");
555}
556
d9cfa2be
AD
557/* The value of %define variable VARIABLE (corresponding to FIELD, if
558 defined). Do not register as used, but diagnose unset variables. */
559
8e13c5c0 560static
d9cfa2be
AD
561char const *
562muscle_percent_define_get_raw (char const *variable, char const *field)
563{
564 uniqstr name = muscle_name (variable, field);
565 char const *res = muscle_find_const (name);
566 if (!res)
567 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
568 "muscle_percent_define_get_raw", quote (variable));
569 return res;
570}
571
f124d423
JD
572char *
573muscle_percent_define_get (char const *variable)
574{
c98b5143 575 uniqstr name = muscle_name (variable, NULL);
1ad6f4da 576 char *value = string_decode (name);
f124d423
JD
577 if (!value)
578 value = xstrdup ("");
0f9583b6 579 muscle_percent_define_use (variable);
f124d423
JD
580 return value;
581}
582
c53b6848
AD
583/* The kind of VARIABLE. An error if undefined. */
584static muscle_kind
585muscle_percent_define_get_kind (char const *variable)
586{
587 return muscle_kind_new (muscle_percent_define_get_raw (variable, "kind"));
588}
589
590/* Check the kind of VARIABLE. An error if undefined. */
591static void
592muscle_percent_define_check_kind (char const *variable, muscle_kind kind)
593{
594 if (muscle_percent_define_get_kind (variable) != kind)
595 {
596 location loc = muscle_percent_define_get_loc (variable);
597 switch (kind)
598 {
599 case muscle_code:
600 complain (&loc, Wdeprecated,
601 "%%define variable '%s' requires '{...}' values",
602 variable);
603 break;
604 case muscle_keyword:
605 complain (&loc, Wdeprecated,
606 "%%define variable '%s' requires keyword values",
607 variable);
608 break;
609 case muscle_string:
610 complain (&loc, Wdeprecated,
611 "%%define variable '%s' requires '\"...\"' values",
612 variable);
613 break;
614 }
615 }
616}
617
618
35b8730d
JD
619location
620muscle_percent_define_get_loc (char const *variable)
621{
d9cfa2be 622 return location_decode (muscle_percent_define_get_raw (variable, "loc"));
35b8730d
JD
623}
624
625char const *
626muscle_percent_define_get_syncline (char const *variable)
627{
d9cfa2be 628 return muscle_percent_define_get_raw (variable, "syncline");
35b8730d
JD
629}
630
f124d423
JD
631bool
632muscle_percent_define_ifdef (char const *variable)
633{
0f9583b6 634 if (muscle_find_const (muscle_name (variable, NULL)))
f124d423 635 {
0f9583b6 636 muscle_percent_define_use (variable);
f124d423
JD
637 return true;
638 }
0f9583b6
AD
639 else
640 return false;
f124d423
JD
641}
642
9611cfa2
JD
643bool
644muscle_percent_define_flag_if (char const *variable)
645{
c98b5143 646 uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
1ad6f4da 647 bool result = false;
9611cfa2 648
f124d423 649 if (muscle_percent_define_ifdef (variable))
9611cfa2 650 {
f124d423 651 char *value = muscle_percent_define_get (variable);
c53b6848 652 muscle_percent_define_check_kind (variable, muscle_keyword);
f518dbaf 653 if (value[0] == '\0' || STREQ (value, "true"))
9611cfa2 654 result = true;
f518dbaf 655 else if (STREQ (value, "false"))
9611cfa2 656 result = false;
cbd50549
JD
657 else if (!muscle_find_const (invalid_boolean_name))
658 {
659 muscle_insert (invalid_boolean_name, "");
6fb8b256 660 location loc = muscle_percent_define_get_loc (variable);
bb8e56ff
TR
661 complain (&loc, complaint,
662 _("invalid value for %%define Boolean variable %s"),
663 quote (variable));
cbd50549 664 }
f124d423 665 free (value);
9611cfa2
JD
666 }
667 else
bb8e56ff 668 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 669 "muscle_percent_define_flag", quote (variable));
9611cfa2 670
9611cfa2
JD
671 return result;
672}
673
674void
675muscle_percent_define_default (char const *variable, char const *value)
676{
c98b5143 677 uniqstr name = muscle_name (variable, NULL);
9611cfa2
JD
678 if (!muscle_find_const (name))
679 {
9611cfa2 680 MUSCLE_INSERT_STRING (name, value);
c53b6848 681 MUSCLE_INSERT_STRING (muscle_name (variable, "kind"), "keyword");
7956485c
AD
682 {
683 uniqstr loc_name = muscle_name (variable, "loc");
684 location loc;
685 loc.start.file = loc.end.file = "<default value>";
686 loc.start.line = loc.end.line = -1;
687 loc.start.column = loc.end.column = -1;
688 muscle_insert (loc_name, "");
689 muscle_location_grow (loc_name, loc);
690 }
691 muscle_insert (muscle_name (variable, "syncline"), "");
9611cfa2
JD
692 }
693}
694
f124d423 695void
b1a81613 696muscle_percent_define_check_values (char const * const *values)
f124d423 697{
b1a81613
JD
698 for (; *values; ++values)
699 {
f4909773 700 char const * const *variablep = values;
c98b5143 701 uniqstr name = muscle_name (*variablep, NULL);
1ad6f4da 702 char *value = string_decode (name);
c53b6848 703 muscle_percent_define_check_kind (*variablep, muscle_keyword);
b1a81613
JD
704 if (value)
705 {
b1a81613
JD
706 for (++values; *values; ++values)
707 {
f518dbaf 708 if (STREQ (value, *values))
f4909773
JD
709 break;
710 }
711 if (!*values)
712 {
a974c1ec 713 unsigned i = 0;
f4909773 714 location loc = muscle_percent_define_get_loc (*variablep);
b999409e
TR
715 complain_indent (&loc, complaint, &i,
716 _("invalid value for %%define variable %s: %s"),
717 quote (*variablep), quote_n (1, value));
a974c1ec 718 i += SUB_INDENT;
f4909773 719 for (values = variablep + 1; *values; ++values)
219458e2 720 complain_indent (&loc, complaint | no_caret | silent, &i,
ea9e670d 721 _("accepted value: %s"), quote (*values));
f4909773
JD
722 }
723 else
724 {
725 while (*values)
726 ++values;
b1a81613 727 }
b1a81613
JD
728 free (value);
729 }
730 else
bb8e56ff 731 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 732 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 733 }
f124d423
JD
734}
735
9611cfa2
JD
736void
737muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
738 char const *code, location code_loc)
739{
1ad6f4da 740 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
741 muscle_code_grow (name, code, code_loc);
742 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
743 qualifier_loc);
744}
745
746
ae7453f2
AD
747/*------------------------------------------------.
748| Output the definition of ENTRY as a m4_define. |
749`------------------------------------------------*/
be2a1a68 750
e00b6826 751static inline bool
8322e8f5 752muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68 753{
1ad6f4da
AD
754 fprintf (out,
755 "m4_define([b4_%s],\n"
756 "[[%s]])\n\n\n", entry->key, entry->value);
e00b6826
PE
757 return true;
758}
759
760static bool
761muscle_m4_output_processor (void *entry, void *out)
762{
763 return muscle_m4_output (entry, out);
be2a1a68
AD
764}
765
766
be2a1a68
AD
767void
768muscles_m4_output (FILE *out)
769{
e00b6826 770 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 771}