]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
muscle: enforce definition syntax for keyword variables
[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
560char const *
561muscle_percent_define_get_raw (char const *variable, char const *field)
562{
563 uniqstr name = muscle_name (variable, field);
564 char const *res = muscle_find_const (name);
565 if (!res)
566 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
567 "muscle_percent_define_get_raw", quote (variable));
568 return res;
569}
570
f124d423
JD
571char *
572muscle_percent_define_get (char const *variable)
573{
c98b5143 574 uniqstr name = muscle_name (variable, NULL);
1ad6f4da 575 char *value = string_decode (name);
f124d423
JD
576 if (!value)
577 value = xstrdup ("");
0f9583b6 578 muscle_percent_define_use (variable);
f124d423
JD
579 return value;
580}
581
c53b6848
AD
582/* The kind of VARIABLE. An error if undefined. */
583static muscle_kind
584muscle_percent_define_get_kind (char const *variable)
585{
586 return muscle_kind_new (muscle_percent_define_get_raw (variable, "kind"));
587}
588
589/* Check the kind of VARIABLE. An error if undefined. */
590static void
591muscle_percent_define_check_kind (char const *variable, muscle_kind kind)
592{
593 if (muscle_percent_define_get_kind (variable) != kind)
594 {
595 location loc = muscle_percent_define_get_loc (variable);
596 switch (kind)
597 {
598 case muscle_code:
599 complain (&loc, Wdeprecated,
600 "%%define variable '%s' requires '{...}' values",
601 variable);
602 break;
603 case muscle_keyword:
604 complain (&loc, Wdeprecated,
605 "%%define variable '%s' requires keyword values",
606 variable);
607 break;
608 case muscle_string:
609 complain (&loc, Wdeprecated,
610 "%%define variable '%s' requires '\"...\"' values",
611 variable);
612 break;
613 }
614 }
615}
616
617
35b8730d
JD
618location
619muscle_percent_define_get_loc (char const *variable)
620{
d9cfa2be 621 return location_decode (muscle_percent_define_get_raw (variable, "loc"));
35b8730d
JD
622}
623
624char const *
625muscle_percent_define_get_syncline (char const *variable)
626{
d9cfa2be 627 return muscle_percent_define_get_raw (variable, "syncline");
35b8730d
JD
628}
629
f124d423
JD
630bool
631muscle_percent_define_ifdef (char const *variable)
632{
0f9583b6 633 if (muscle_find_const (muscle_name (variable, NULL)))
f124d423 634 {
0f9583b6 635 muscle_percent_define_use (variable);
f124d423
JD
636 return true;
637 }
0f9583b6
AD
638 else
639 return false;
f124d423
JD
640}
641
9611cfa2
JD
642bool
643muscle_percent_define_flag_if (char const *variable)
644{
c98b5143 645 uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
1ad6f4da 646 bool result = false;
9611cfa2 647
f124d423 648 if (muscle_percent_define_ifdef (variable))
9611cfa2 649 {
f124d423 650 char *value = muscle_percent_define_get (variable);
c53b6848 651 muscle_percent_define_check_kind (variable, muscle_keyword);
f518dbaf 652 if (value[0] == '\0' || STREQ (value, "true"))
9611cfa2 653 result = true;
f518dbaf 654 else if (STREQ (value, "false"))
9611cfa2 655 result = false;
cbd50549
JD
656 else if (!muscle_find_const (invalid_boolean_name))
657 {
658 muscle_insert (invalid_boolean_name, "");
6fb8b256 659 location loc = muscle_percent_define_get_loc (variable);
bb8e56ff
TR
660 complain (&loc, complaint,
661 _("invalid value for %%define Boolean variable %s"),
662 quote (variable));
cbd50549 663 }
f124d423 664 free (value);
9611cfa2
JD
665 }
666 else
bb8e56ff 667 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 668 "muscle_percent_define_flag", quote (variable));
9611cfa2 669
9611cfa2
JD
670 return result;
671}
672
673void
674muscle_percent_define_default (char const *variable, char const *value)
675{
c98b5143 676 uniqstr name = muscle_name (variable, NULL);
9611cfa2
JD
677 if (!muscle_find_const (name))
678 {
9611cfa2 679 MUSCLE_INSERT_STRING (name, value);
c53b6848 680 MUSCLE_INSERT_STRING (muscle_name (variable, "kind"), "keyword");
7956485c
AD
681 {
682 uniqstr loc_name = muscle_name (variable, "loc");
683 location loc;
684 loc.start.file = loc.end.file = "<default value>";
685 loc.start.line = loc.end.line = -1;
686 loc.start.column = loc.end.column = -1;
687 muscle_insert (loc_name, "");
688 muscle_location_grow (loc_name, loc);
689 }
690 muscle_insert (muscle_name (variable, "syncline"), "");
9611cfa2
JD
691 }
692}
693
f124d423 694void
b1a81613 695muscle_percent_define_check_values (char const * const *values)
f124d423 696{
b1a81613
JD
697 for (; *values; ++values)
698 {
f4909773 699 char const * const *variablep = values;
c98b5143 700 uniqstr name = muscle_name (*variablep, NULL);
1ad6f4da 701 char *value = string_decode (name);
c53b6848 702 muscle_percent_define_check_kind (*variablep, muscle_keyword);
b1a81613
JD
703 if (value)
704 {
b1a81613
JD
705 for (++values; *values; ++values)
706 {
f518dbaf 707 if (STREQ (value, *values))
f4909773
JD
708 break;
709 }
710 if (!*values)
711 {
a974c1ec 712 unsigned i = 0;
f4909773 713 location loc = muscle_percent_define_get_loc (*variablep);
b999409e
TR
714 complain_indent (&loc, complaint, &i,
715 _("invalid value for %%define variable %s: %s"),
716 quote (*variablep), quote_n (1, value));
a974c1ec 717 i += SUB_INDENT;
f4909773 718 for (values = variablep + 1; *values; ++values)
219458e2 719 complain_indent (&loc, complaint | no_caret | silent, &i,
ea9e670d 720 _("accepted value: %s"), quote (*values));
f4909773
JD
721 }
722 else
723 {
724 while (*values)
725 ++values;
b1a81613 726 }
b1a81613
JD
727 free (value);
728 }
729 else
bb8e56ff 730 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 731 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 732 }
f124d423
JD
733}
734
9611cfa2
JD
735void
736muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
737 char const *code, location code_loc)
738{
1ad6f4da 739 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
740 muscle_code_grow (name, code, code_loc);
741 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
742 qualifier_loc);
743}
744
745
ae7453f2
AD
746/*------------------------------------------------.
747| Output the definition of ENTRY as a m4_define. |
748`------------------------------------------------*/
be2a1a68 749
e00b6826 750static inline bool
8322e8f5 751muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68 752{
1ad6f4da
AD
753 fprintf (out,
754 "m4_define([b4_%s],\n"
755 "[[%s]])\n\n\n", entry->key, entry->value);
e00b6826
PE
756 return true;
757}
758
759static bool
760muscle_m4_output_processor (void *entry, void *out)
761{
762 return muscle_m4_output (entry, out);
be2a1a68
AD
763}
764
765
be2a1a68
AD
766void
767muscles_m4_output (FILE *out)
768{
e00b6826 769 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 770}