]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
List accepted values for a %define enum variable with an invalid value.
[bison.git] / src / muscle-tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
4920ae8b
AD
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 Free Software Foundation, Inc.
f753cd62
MA
5
6 This file is part of Bison, the GNU Compiler Compiler.
7
f16b0819 8 This program is free software: you can redistribute it and/or modify
f753cd62 9 it under the terms of the GNU General Public License as published by
f16b0819
PE
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
f753cd62 12
f16b0819 13 This program is distributed in the hope that it will be useful,
f753cd62
MA
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
f16b0819 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
f753cd62 20
2cec9080 21#include <config.h>
f753cd62 22#include "system.h"
8322e8f5
PE
23
24#include <hash.h>
25#include <quotearg.h>
26
9611cfa2 27#include "complain.h"
f753cd62 28#include "files.h"
00f5d575 29#include "muscle-tab.h"
f508cb0a 30#include "getargs.h"
f753cd62 31
eb095650
PE
32/* A key-value pair, along with storage that can be reclaimed when
33 this pair is no longer needed. */
8322e8f5
PE
34typedef struct
35{
eb095650
PE
36 char const *key;
37 char const *value;
38 char *storage;
8322e8f5 39} muscle_entry;
592e8d4d
AD
40
41/* An obstack used to create some entries. */
42struct obstack muscle_obstack;
43
beda758b
AD
44/* Initial capacity of muscles hash table. */
45#define HT_INITIAL_CAPACITY 257
f753cd62 46
04098407 47static struct hash_table *muscle_table = NULL;
f753cd62 48
beda758b
AD
49static bool
50hash_compare_muscles (void const *x, void const *y)
f753cd62 51{
8322e8f5
PE
52 muscle_entry const *m1 = x;
53 muscle_entry const *m2 = y;
5dd5fd4a 54 return strcmp (m1->key, m2->key) == 0;
f753cd62
MA
55}
56
233a88ad
PE
57static size_t
58hash_muscle (const void *x, size_t tablesize)
f753cd62 59{
8322e8f5 60 muscle_entry const *m = x;
beda758b 61 return hash_string (m->key, tablesize);
f753cd62
MA
62}
63
592e8d4d
AD
64/*-----------------------------------------------------------------.
65| Create the MUSCLE_TABLE, and initialize it with default values. |
66| Also set up the MUSCLE_OBSTACK. |
67`-----------------------------------------------------------------*/
68
eb095650
PE
69static void
70muscle_entry_free (void *entry)
71{
72 muscle_entry *mentry = entry;
73 free (mentry->storage);
74 free (mentry);
75}
76
f753cd62
MA
77void
78muscle_init (void)
79{
ae7453f2
AD
80 /* Initialize the muscle obstack. */
81 obstack_init (&muscle_obstack);
82
beda758b 83 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
eb095650 84 hash_compare_muscles, muscle_entry_free);
f753cd62
MA
85
86 /* Version and input file. */
ae7453f2 87 MUSCLE_INSERT_STRING ("version", VERSION);
f753cd62
MA
88}
89
592e8d4d
AD
90
91/*------------------------------------------------------------.
92| Free all the memory consumed by the muscle machinery only. |
93`------------------------------------------------------------*/
94
95void
96muscle_free (void)
97{
98 hash_free (muscle_table);
99 obstack_free (&muscle_obstack, NULL);
100}
101
102
103
ae7453f2
AD
104/*------------------------------------------------------------.
105| Insert (KEY, VALUE). If KEY already existed, overwrite the |
106| previous value. |
107`------------------------------------------------------------*/
108
a870c567 109void
eb095650 110muscle_insert (char const *key, char const *value)
f753cd62 111{
8322e8f5 112 muscle_entry probe;
da2a7671 113 muscle_entry *entry;
e9bca3ad 114
ae7453f2
AD
115 probe.key = key;
116 entry = hash_lookup (muscle_table, &probe);
beda758b
AD
117
118 if (!entry)
119 {
120 /* First insertion in the hash. */
da2a7671 121 entry = xmalloc (sizeof *entry);
beda758b
AD
122 entry->key = key;
123 hash_insert (muscle_table, entry);
124 }
4502eadc
JD
125 else
126 free (entry->storage);
beda758b 127 entry->value = value;
4502eadc 128 entry->storage = NULL;
f753cd62
MA
129}
130
ae7453f2
AD
131
132/*-------------------------------------------------------------------.
ff5150d9
PE
133| Append VALUE to the current value of KEY. If KEY did not already |
134| exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
135| associated value. Copy VALUE and SEPARATOR. |
ae7453f2
AD
136`-------------------------------------------------------------------*/
137
138void
139muscle_grow (const char *key, const char *val, const char *separator)
140{
8322e8f5
PE
141 muscle_entry probe;
142 muscle_entry *entry = NULL;
ae7453f2
AD
143
144 probe.key = key;
145 entry = hash_lookup (muscle_table, &probe);
146
147 if (!entry)
148 {
149 /* First insertion in the hash. */
da2a7671 150 entry = xmalloc (sizeof *entry);
ae7453f2
AD
151 entry->key = key;
152 hash_insert (muscle_table, entry);
eb095650 153 entry->value = entry->storage = xstrdup (val);
ae7453f2
AD
154 }
155 else
156 {
157 /* Grow the current value. */
158 char *new_val;
ae7453f2 159 obstack_sgrow (&muscle_obstack, entry->value);
eb095650 160 free (entry->storage);
ae7453f2
AD
161 obstack_sgrow (&muscle_obstack, separator);
162 obstack_sgrow (&muscle_obstack, val);
163 obstack_1grow (&muscle_obstack, 0);
164 new_val = obstack_finish (&muscle_obstack);
eb095650 165 entry->value = entry->storage = xstrdup (new_val);
ae7453f2
AD
166 obstack_free (&muscle_obstack, new_val);
167 }
168}
169
cd3684cf 170/*------------------------------------------------------------------.
35b8730d
JD
171| Using muscle_grow, append a synchronization line for the location |
172| LOC to the current value of KEY. |
cd3684cf
AD
173`------------------------------------------------------------------*/
174
35b8730d
JD
175static void
176muscle_syncline_grow (char const *key, location loc)
cd3684cf
AD
177{
178 char *extension = NULL;
05ac60f3 179 obstack_fgrow1 (&muscle_obstack, "]b4_syncline(%d, [[", loc.start.line);
cd3684cf
AD
180 MUSCLE_OBSTACK_SGROW (&muscle_obstack,
181 quotearg_style (c_quoting_style, loc.start.file));
35b8730d 182 obstack_sgrow (&muscle_obstack, "]])[");
cd3684cf
AD
183 obstack_1grow (&muscle_obstack, 0);
184 extension = obstack_finish (&muscle_obstack);
185 muscle_grow (key, extension, "");
eb095650 186 obstack_free (&muscle_obstack, extension);
cd3684cf
AD
187}
188
35b8730d
JD
189/*------------------------------------------------------------------.
190| Append VALUE to the current value of KEY, using muscle_grow. But |
191| in addition, issue a synchronization line for the location LOC |
192| using muscle_syncline_grow. |
193`------------------------------------------------------------------*/
194
195void
196muscle_code_grow (const char *key, const char *val, location loc)
197{
198 muscle_syncline_grow (key, loc);
199 muscle_grow (key, val, "\n");
200}
201
cd3684cf 202
ae7453f2
AD
203void muscle_pair_list_grow (const char *muscle,
204 const char *a1, const char *a2)
205{
66d30cd4 206 char *pair;
7ecec4dd
JD
207 obstack_sgrow (&muscle_obstack, "[[[");
208 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a1);
209 obstack_sgrow (&muscle_obstack, "]], [[");
210 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a2);
211 obstack_sgrow (&muscle_obstack, "]]]");
ae7453f2 212 obstack_1grow (&muscle_obstack, 0);
66d30cd4
AD
213 pair = obstack_finish (&muscle_obstack);
214 muscle_grow (muscle, pair, ",\n");
215 obstack_free (&muscle_obstack, pair);
ae7453f2
AD
216}
217
7eb8a0bc
JD
218
219/*----------------------------------------------------------------------------.
220| Find the value of muscle KEY. Unlike MUSCLE_FIND, this is always reliable |
221| to determine whether KEY has a value. |
222`----------------------------------------------------------------------------*/
223
224char const *
225muscle_find_const (char const *key)
226{
227 muscle_entry probe;
228 muscle_entry *result = NULL;
229
230 probe.key = key;
231 result = hash_lookup (muscle_table, &probe);
232 if (result)
233 return result->value;
234 return NULL;
235}
236
237
4502eadc
JD
238/*----------------------------------------------------------------------------.
239| Find the value of muscle KEY. Abort if muscle_insert was invoked more |
240| recently than muscle_grow for KEY since muscle_find can't return a |
241| char const *. |
242`----------------------------------------------------------------------------*/
ae7453f2 243
ff5150d9 244char *
7eb8a0bc 245muscle_find (char const *key)
f753cd62 246{
8322e8f5
PE
247 muscle_entry probe;
248 muscle_entry *result = NULL;
e9bca3ad 249
ae7453f2
AD
250 probe.key = key;
251 result = hash_lookup (muscle_table, &probe);
4502eadc
JD
252 if (result)
253 {
254 aver (result->value == result->storage);
255 return result->storage;
256 }
257 return NULL;
f753cd62 258}
be2a1a68
AD
259
260
9611cfa2
JD
261void
262muscle_boundary_grow (char const *key, boundary bound)
263{
264 char *extension;
265 MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file);
266 obstack_1grow (&muscle_obstack, ':');
267 obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
268 obstack_1grow (&muscle_obstack, '.');
269 obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
270 obstack_1grow (&muscle_obstack, '\0');
271 extension = obstack_finish (&muscle_obstack);
272 muscle_grow (key, extension, "");
273 obstack_free (&muscle_obstack, extension);
274}
275
276void
277muscle_location_grow (char const *key, location loc)
278{
279 muscle_grow (key, "[[", "");
280 muscle_boundary_grow (key, loc.start);
281 muscle_grow (key, "]], [[", "");
282 muscle_boundary_grow (key, loc.end);
283 muscle_grow (key, "]]", "");
284}
285
f124d423
JD
286#define MUSCLE_COMMON_DECODE(Value) \
287 case '$': \
288 aver (*++(Value) == ']'); \
289 aver (*++(Value) == '['); \
290 obstack_sgrow (&muscle_obstack, "$"); \
291 break; \
292 case '@': \
293 switch (*++(Value)) \
294 { \
295 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
296 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
297 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
298 default: aver (false); break; \
299 } \
300 break; \
301 default: \
302 obstack_1grow (&muscle_obstack, *(Value)); \
303 break;
304
305/* Reverse of MUSCLE_OBSTACK_SGROW. */
306static char *
307muscle_string_decode (char const *key)
308{
309 char const *value;
310 char *value_decoded;
311 char *result;
312
313 value = muscle_find_const (key);
314 if (!value)
315 return NULL;
316 do {
317 switch (*value)
318 {
319 MUSCLE_COMMON_DECODE (value)
320 case '[':
321 case ']':
322 aver (false);
323 break;
324 }
325 } while (*value++);
326 value_decoded = obstack_finish (&muscle_obstack);
327 result = xstrdup (value_decoded);
328 obstack_free (&muscle_obstack, value_decoded);
329 return result;
330}
331
9611cfa2
JD
332/* Reverse of muscle_location_grow. */
333static location
334muscle_location_decode (char const *key)
335{
336 location loc;
337 char const *value = muscle_find_const (key);
338 aver (value);
339 aver (*value == '[');
340 aver (*++value == '[');
341 while (*++value)
342 switch (*value)
343 {
f124d423 344 MUSCLE_COMMON_DECODE (value)
9611cfa2
JD
345 case '[':
346 aver (false);
347 break;
348 case ']':
349 {
350 char *boundary_str;
351 aver (*++value == ']');
352 obstack_1grow (&muscle_obstack, '\0');
353 boundary_str = obstack_finish (&muscle_obstack);
354 switch (*++value)
355 {
356 case ',':
357 boundary_set_from_string (&loc.start, boundary_str);
358 obstack_free (&muscle_obstack, boundary_str);
359 aver (*++value == ' ');
360 aver (*++value == '[');
361 aver (*++value == '[');
362 break;
363 case '\0':
364 boundary_set_from_string (&loc.end, boundary_str);
365 obstack_free (&muscle_obstack, boundary_str);
366 return loc;
367 break;
368 default:
369 aver (false);
370 break;
371 }
372 }
373 break;
9611cfa2
JD
374 }
375 aver (false);
376 return loc;
377}
378
379void
380muscle_user_name_list_grow (char const *key, char const *user_name,
381 location loc)
382{
383 muscle_grow (key, "[[[[", ",");
384 muscle_grow (key, user_name, "");
385 muscle_grow (key, "]], ", "");
386 muscle_location_grow (key, loc);
387 muscle_grow (key, "]]", "");
388}
389
390#define MUSCLE_USER_NAME_CONVERT(NAME, PREFIX, USER_NAME, SUFFIX) \
391do { \
392 char *tmp; \
393 size_t length = strlen ((USER_NAME)); \
394 tmp = xmalloc (sizeof (PREFIX) - 1 + length + sizeof (SUFFIX)); \
395 strcpy (tmp, (PREFIX)); \
396 strcpy (tmp + sizeof (PREFIX) - 1, (USER_NAME)); \
397 strcpy (tmp + sizeof (PREFIX) - 1 + length, (SUFFIX)); \
398 (NAME) = uniqstr_new (tmp); \
399 free (tmp); \
400} while (0)
401
402void
403muscle_percent_define_insert (char const *variable, location variable_loc,
404 char const *value)
405{
406 char const *name;
407 char const *loc_name;
35b8730d 408 char const *syncline_name;
9611cfa2
JD
409
410 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
411 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
412 MUSCLE_USER_NAME_CONVERT (syncline_name,
413 "percent_define_syncline(", variable, ")");
9611cfa2
JD
414
415 if (muscle_find_const (name))
416 {
417 warn_at (variable_loc, _("%s `%s' redefined"),
418 "%define variable", variable);
35b8730d
JD
419 warn_at (muscle_percent_define_get_loc (variable),
420 _("previous definition"));
9611cfa2
JD
421 }
422 MUSCLE_INSERT_STRING (name, value);
423
424 muscle_insert (loc_name, "");
425 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
426 muscle_insert (syncline_name, "");
427 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
428 muscle_user_name_list_grow ("percent_define_user_variables", variable,
429 variable_loc);
430}
431
4920ae8b
AD
432/* This is used for backward compatibility, e.g., "%define api.pure"
433 supersedes "%pure-parser". */
434void
435muscle_percent_define_ensure (char const *variable, location loc,
436 bool value)
437{
438 char const *val = value ? "" : "false";
439 char const *name;
440 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
441
442 /* %pure-parser is deprecated in favor of `%define api.pure', so use
443 `%define api.pure' in a backward-compatible manner here. First,
444 don't complain if %pure-parser is specified multiple times. */
445 if (!muscle_find_const (name))
446 muscle_percent_define_insert (variable, loc, val);
447 /* In all cases, use api.pure now so that the backend doesn't complain if
448 the skeleton ignores api.pure, but do warn now if there's a previous
449 conflicting definition from an actual %define. */
450 if (muscle_percent_define_flag_if (variable) != value)
451 muscle_percent_define_insert (variable, loc, val);
452}
453
f124d423
JD
454char *
455muscle_percent_define_get (char const *variable)
456{
457 char const *name;
458 char const *usage_name;
459 char *value;
460
461 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
462 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
463 variable, ")");
464
465 muscle_insert (usage_name, "");
466 value = muscle_string_decode (name);
467 if (!value)
468 value = xstrdup ("");
469 return value;
470}
471
35b8730d
JD
472location
473muscle_percent_define_get_loc (char const *variable)
474{
475 char const *loc_name;
476 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
477 if (!muscle_find_const (loc_name))
478 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_loc"),
479 variable);
480 return muscle_location_decode (loc_name);
481}
482
483char const *
484muscle_percent_define_get_syncline (char const *variable)
485{
486 char const *syncline_name;
487 char const *syncline;
488 MUSCLE_USER_NAME_CONVERT (syncline_name,
489 "percent_define_syncline(", variable, ")");
490 syncline = muscle_find_const (syncline_name);
491 if (!syncline)
492 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_syncline"),
493 variable);
494 return syncline;
495}
496
f124d423
JD
497bool
498muscle_percent_define_ifdef (char const *variable)
499{
500 char const *name;
501 char const *usage_name;
502 char const *value;
503
504 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
505 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
506 variable, ")");
507
508 value = muscle_find_const (name);
509 if (value)
510 {
511 muscle_insert (usage_name, "");
512 return true;
513 }
514
515 return false;
516}
517
9611cfa2
JD
518bool
519muscle_percent_define_flag_if (char const *variable)
520{
cbd50549 521 char const *invalid_boolean_name;
9611cfa2
JD
522 bool result = false;
523
cbd50549
JD
524 MUSCLE_USER_NAME_CONVERT (invalid_boolean_name,
525 "percent_define_invalid_boolean(", variable, ")");
9611cfa2 526
f124d423 527 if (muscle_percent_define_ifdef (variable))
9611cfa2 528 {
f124d423 529 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
530 if (value[0] == '\0' || 0 == strcmp (value, "true"))
531 result = true;
532 else if (0 == strcmp (value, "false"))
533 result = false;
cbd50549
JD
534 else if (!muscle_find_const (invalid_boolean_name))
535 {
536 muscle_insert (invalid_boolean_name, "");
35b8730d 537 complain_at(muscle_percent_define_get_loc (variable),
922bdd7f 538 _("invalid value for %%define Boolean variable `%s'"),
cbd50549
JD
539 variable);
540 }
f124d423 541 free (value);
9611cfa2
JD
542 }
543 else
544 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
545 variable);
546
9611cfa2
JD
547 return result;
548}
549
550void
551muscle_percent_define_default (char const *variable, char const *value)
552{
553 char const *name;
554 char const *loc_name;
35b8730d 555 char const *syncline_name;
9611cfa2
JD
556 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
557 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
558 MUSCLE_USER_NAME_CONVERT (syncline_name,
559 "percent_define_syncline(", variable, ")");
9611cfa2
JD
560 if (!muscle_find_const (name))
561 {
562 location loc;
563 MUSCLE_INSERT_STRING (name, value);
92822aff
JD
564 loc.start.file = loc.end.file = "<default value>";
565 loc.start.line = loc.end.line = -1;
566 loc.start.column = loc.end.column = -1;
9611cfa2
JD
567 muscle_insert (loc_name, "");
568 muscle_location_grow (loc_name, loc);
35b8730d 569 muscle_insert (syncline_name, "");
9611cfa2
JD
570 }
571}
572
f124d423 573void
b1a81613 574muscle_percent_define_check_values (char const * const *values)
f124d423 575{
b1a81613
JD
576 for (; *values; ++values)
577 {
f4909773 578 char const * const *variablep = values;
b1a81613 579 char const *name;
b1a81613
JD
580 char *value;
581
f4909773 582 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", *variablep, ")");
b1a81613
JD
583
584 value = muscle_string_decode (name);
585 if (value)
586 {
b1a81613
JD
587 for (++values; *values; ++values)
588 {
589 if (0 == strcmp (value, *values))
f4909773
JD
590 break;
591 }
592 if (!*values)
593 {
594 location loc = muscle_percent_define_get_loc (*variablep);
595 complain_at(loc,
596 _("invalid value for %%define variable `%s': `%s'"),
597 *variablep, value);
598 for (values = variablep + 1; *values; ++values)
599 complain_at (loc, _("accepted value: `%s'"), *values);
600 }
601 else
602 {
603 while (*values)
604 ++values;
b1a81613 605 }
b1a81613
JD
606 free (value);
607 }
608 else
f4909773
JD
609 fatal(_("undefined %%define variable `%s' passed to"
610 " muscle_percent_define_check_values"),
611 *variablep);
b1a81613 612 }
f124d423
JD
613}
614
9611cfa2
JD
615void
616muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
617 char const *code, location code_loc)
618{
619 char const *name;
620 MUSCLE_USER_NAME_CONVERT (name, "percent_code(", qualifier, ")");
621 muscle_code_grow (name, code, code_loc);
622 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
623 qualifier_loc);
624}
625
626
ae7453f2
AD
627/*------------------------------------------------.
628| Output the definition of ENTRY as a m4_define. |
629`------------------------------------------------*/
be2a1a68 630
e00b6826 631static inline bool
8322e8f5 632muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
633{
634 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 635 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
636 return true;
637}
638
639static bool
640muscle_m4_output_processor (void *entry, void *out)
641{
642 return muscle_m4_output (entry, out);
be2a1a68
AD
643}
644
645
ae7453f2
AD
646/*----------------------------------------------------------------.
647| Output the definition of all the current muscles into a list of |
648| m4_defines. |
649`----------------------------------------------------------------*/
be2a1a68
AD
650
651void
652muscles_m4_output (FILE *out)
653{
e00b6826 654 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 655}