]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
muscle: factor the handling of used 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
c1cc91bd 347location_decode (char const *key)
9611cfa2
JD
348{
349 location loc;
350 char const *value = muscle_find_const (key);
351 aver (value);
352 aver (*value == '[');
353 aver (*++value == '[');
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;
364 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);
371 aver (*++value == ' ');
372 aver (*++value == '[');
373 aver (*++value == '[');
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. */
4920ae8b 545 if (!muscle_find_const (name))
14bfd2e9 546 muscle_percent_define_insert (variable, loc, muscle_keyword, val,
de5ab940 547 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b 548 if (muscle_percent_define_flag_if (variable) != value)
14bfd2e9 549 muscle_percent_define_insert (variable, loc, muscle_keyword, val,
de5ab940 550 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
4920ae8b
AD
551}
552
0f9583b6
AD
553/* Mark %define VARIABLE as used. */
554static void
555muscle_percent_define_use (char const *variable)
556{
557 muscle_insert (muscle_name (variable, "bison_variables"), "");
558}
559
f124d423
JD
560char *
561muscle_percent_define_get (char const *variable)
562{
c98b5143 563 uniqstr name = muscle_name (variable, NULL);
1ad6f4da 564 char *value = string_decode (name);
f124d423
JD
565 if (!value)
566 value = xstrdup ("");
0f9583b6 567 muscle_percent_define_use (variable);
f124d423
JD
568 return value;
569}
570
35b8730d
JD
571location
572muscle_percent_define_get_loc (char const *variable)
573{
c98b5143 574 uniqstr loc_name = muscle_name (variable, "loc");
35b8730d 575 if (!muscle_find_const (loc_name))
bb8e56ff 576 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 577 "muscle_percent_define_get_loc", quote (variable));
c1cc91bd 578 return location_decode (loc_name);
35b8730d
JD
579}
580
581char const *
582muscle_percent_define_get_syncline (char const *variable)
583{
c98b5143 584 uniqstr syncline_name = muscle_name (variable, "syncline");
1ad6f4da 585 char const *syncline = muscle_find_const (syncline_name);
35b8730d 586 if (!syncline)
bb8e56ff 587 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
1ad6f4da 588 "muscle_percent_define_get_syncline", quote (variable));
35b8730d
JD
589 return syncline;
590}
591
f124d423
JD
592bool
593muscle_percent_define_ifdef (char const *variable)
594{
0f9583b6 595 if (muscle_find_const (muscle_name (variable, NULL)))
f124d423 596 {
0f9583b6 597 muscle_percent_define_use (variable);
f124d423
JD
598 return true;
599 }
0f9583b6
AD
600 else
601 return false;
f124d423
JD
602}
603
9611cfa2
JD
604bool
605muscle_percent_define_flag_if (char const *variable)
606{
c98b5143 607 uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
1ad6f4da 608 bool result = false;
9611cfa2 609
f124d423 610 if (muscle_percent_define_ifdef (variable))
9611cfa2 611 {
f124d423 612 char *value = muscle_percent_define_get (variable);
f518dbaf 613 if (value[0] == '\0' || STREQ (value, "true"))
9611cfa2 614 result = true;
f518dbaf 615 else if (STREQ (value, "false"))
9611cfa2 616 result = false;
cbd50549
JD
617 else if (!muscle_find_const (invalid_boolean_name))
618 {
619 muscle_insert (invalid_boolean_name, "");
6fb8b256 620 location loc = muscle_percent_define_get_loc (variable);
bb8e56ff
TR
621 complain (&loc, complaint,
622 _("invalid value for %%define Boolean variable %s"),
623 quote (variable));
cbd50549 624 }
f124d423 625 free (value);
9611cfa2
JD
626 }
627 else
bb8e56ff 628 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 629 "muscle_percent_define_flag", quote (variable));
9611cfa2 630
9611cfa2
JD
631 return result;
632}
633
634void
635muscle_percent_define_default (char const *variable, char const *value)
636{
c98b5143
AD
637 uniqstr name = muscle_name (variable, NULL);
638 uniqstr loc_name = muscle_name (variable, "loc");
639 uniqstr syncline_name = muscle_name (variable, "syncline");
9611cfa2
JD
640 if (!muscle_find_const (name))
641 {
642 location loc;
643 MUSCLE_INSERT_STRING (name, value);
92822aff
JD
644 loc.start.file = loc.end.file = "<default value>";
645 loc.start.line = loc.end.line = -1;
646 loc.start.column = loc.end.column = -1;
9611cfa2
JD
647 muscle_insert (loc_name, "");
648 muscle_location_grow (loc_name, loc);
35b8730d 649 muscle_insert (syncline_name, "");
9611cfa2
JD
650 }
651}
652
f124d423 653void
b1a81613 654muscle_percent_define_check_values (char const * const *values)
f124d423 655{
b1a81613
JD
656 for (; *values; ++values)
657 {
f4909773 658 char const * const *variablep = values;
c98b5143 659 uniqstr name = muscle_name (*variablep, NULL);
1ad6f4da 660 char *value = string_decode (name);
b1a81613
JD
661 if (value)
662 {
b1a81613
JD
663 for (++values; *values; ++values)
664 {
f518dbaf 665 if (STREQ (value, *values))
f4909773
JD
666 break;
667 }
668 if (!*values)
669 {
a974c1ec 670 unsigned i = 0;
f4909773 671 location loc = muscle_percent_define_get_loc (*variablep);
b999409e
TR
672 complain_indent (&loc, complaint, &i,
673 _("invalid value for %%define variable %s: %s"),
674 quote (*variablep), quote_n (1, value));
a974c1ec 675 i += SUB_INDENT;
f4909773 676 for (values = variablep + 1; *values; ++values)
219458e2 677 complain_indent (&loc, complaint | no_caret | silent, &i,
ea9e670d 678 _("accepted value: %s"), quote (*values));
f4909773
JD
679 }
680 else
681 {
682 while (*values)
683 ++values;
b1a81613 684 }
b1a81613
JD
685 free (value);
686 }
687 else
bb8e56ff 688 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
6fb8b256 689 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 690 }
f124d423
JD
691}
692
9611cfa2
JD
693void
694muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
695 char const *code, location code_loc)
696{
1ad6f4da 697 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
698 muscle_code_grow (name, code, code_loc);
699 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
700 qualifier_loc);
701}
702
703
ae7453f2
AD
704/*------------------------------------------------.
705| Output the definition of ENTRY as a m4_define. |
706`------------------------------------------------*/
be2a1a68 707
e00b6826 708static inline bool
8322e8f5 709muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68 710{
1ad6f4da
AD
711 fprintf (out,
712 "m4_define([b4_%s],\n"
713 "[[%s]])\n\n\n", entry->key, entry->value);
e00b6826
PE
714 return true;
715}
716
717static bool
718muscle_m4_output_processor (void *entry, void *out)
719{
720 return muscle_m4_output (entry, out);
be2a1a68
AD
721}
722
723
be2a1a68
AD
724void
725muscles_m4_output (FILE *out)
726{
e00b6826 727 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 728}