]> git.saurik.com Git - bison.git/blame - src/muscle_tab.c
portability: use va_start and va_end in the same function.
[bison.git] / src / muscle_tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
580c075d 3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Free Software
05ac60f3 4 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
MA
28#include "files.h"
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);
48b16bbc 88 MUSCLE_INSERT_C_STRING ("file_name", grammar_file);
f753cd62
MA
89}
90
592e8d4d
AD
91
92/*------------------------------------------------------------.
93| Free all the memory consumed by the muscle machinery only. |
94`------------------------------------------------------------*/
95
96void
97muscle_free (void)
98{
99 hash_free (muscle_table);
100 obstack_free (&muscle_obstack, NULL);
101}
102
103
104
ae7453f2
AD
105/*------------------------------------------------------------.
106| Insert (KEY, VALUE). If KEY already existed, overwrite the |
107| previous value. |
108`------------------------------------------------------------*/
109
a870c567 110void
eb095650 111muscle_insert (char const *key, char const *value)
f753cd62 112{
8322e8f5 113 muscle_entry probe;
da2a7671 114 muscle_entry *entry;
e9bca3ad 115
ae7453f2
AD
116 probe.key = key;
117 entry = hash_lookup (muscle_table, &probe);
beda758b
AD
118
119 if (!entry)
120 {
121 /* First insertion in the hash. */
da2a7671 122 entry = xmalloc (sizeof *entry);
beda758b 123 entry->key = key;
914e713d
AD
124 if (!hash_insert (muscle_table, entry))
125 xalloc_die ();
beda758b 126 }
4502eadc
JD
127 else
128 free (entry->storage);
beda758b 129 entry->value = value;
4502eadc 130 entry->storage = NULL;
f753cd62
MA
131}
132
ae7453f2
AD
133
134/*-------------------------------------------------------------------.
ff5150d9
PE
135| Append VALUE to the current value of KEY. If KEY did not already |
136| exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
137| associated value. Copy VALUE and SEPARATOR. |
ae7453f2
AD
138`-------------------------------------------------------------------*/
139
140void
141muscle_grow (const char *key, const char *val, const char *separator)
142{
8322e8f5
PE
143 muscle_entry probe;
144 muscle_entry *entry = NULL;
ae7453f2
AD
145
146 probe.key = key;
147 entry = hash_lookup (muscle_table, &probe);
148
149 if (!entry)
150 {
151 /* First insertion in the hash. */
da2a7671 152 entry = xmalloc (sizeof *entry);
ae7453f2 153 entry->key = key;
914e713d
AD
154 if (!hash_insert (muscle_table, entry))
155 xalloc_die ();
eb095650 156 entry->value = entry->storage = xstrdup (val);
ae7453f2
AD
157 }
158 else
159 {
160 /* Grow the current value. */
161 char *new_val;
ae7453f2 162 obstack_sgrow (&muscle_obstack, entry->value);
eb095650 163 free (entry->storage);
ae7453f2
AD
164 obstack_sgrow (&muscle_obstack, separator);
165 obstack_sgrow (&muscle_obstack, val);
166 obstack_1grow (&muscle_obstack, 0);
167 new_val = obstack_finish (&muscle_obstack);
eb095650 168 entry->value = entry->storage = xstrdup (new_val);
ae7453f2
AD
169 obstack_free (&muscle_obstack, new_val);
170 }
171}
172
cd3684cf 173/*------------------------------------------------------------------.
35b8730d
JD
174| Using muscle_grow, append a synchronization line for the location |
175| LOC to the current value of KEY. |
cd3684cf
AD
176`------------------------------------------------------------------*/
177
35b8730d
JD
178static void
179muscle_syncline_grow (char const *key, location loc)
cd3684cf
AD
180{
181 char *extension = NULL;
05ac60f3 182 obstack_fgrow1 (&muscle_obstack, "]b4_syncline(%d, [[", loc.start.line);
cd3684cf
AD
183 MUSCLE_OBSTACK_SGROW (&muscle_obstack,
184 quotearg_style (c_quoting_style, loc.start.file));
35b8730d 185 obstack_sgrow (&muscle_obstack, "]])[");
cd3684cf
AD
186 obstack_1grow (&muscle_obstack, 0);
187 extension = obstack_finish (&muscle_obstack);
188 muscle_grow (key, extension, "");
eb095650 189 obstack_free (&muscle_obstack, extension);
cd3684cf
AD
190}
191
35b8730d
JD
192/*------------------------------------------------------------------.
193| Append VALUE to the current value of KEY, using muscle_grow. But |
194| in addition, issue a synchronization line for the location LOC |
195| using muscle_syncline_grow. |
196`------------------------------------------------------------------*/
197
198void
199muscle_code_grow (const char *key, const char *val, location loc)
200{
201 muscle_syncline_grow (key, loc);
202 muscle_grow (key, val, "\n");
203}
204
cd3684cf 205
ae7453f2
AD
206void muscle_pair_list_grow (const char *muscle,
207 const char *a1, const char *a2)
208{
66d30cd4 209 char *pair;
7ecec4dd
JD
210 obstack_sgrow (&muscle_obstack, "[[[");
211 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a1);
212 obstack_sgrow (&muscle_obstack, "]], [[");
213 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a2);
214 obstack_sgrow (&muscle_obstack, "]]]");
ae7453f2 215 obstack_1grow (&muscle_obstack, 0);
66d30cd4
AD
216 pair = obstack_finish (&muscle_obstack);
217 muscle_grow (muscle, pair, ",\n");
218 obstack_free (&muscle_obstack, pair);
ae7453f2
AD
219}
220
7eb8a0bc
JD
221
222/*----------------------------------------------------------------------------.
223| Find the value of muscle KEY. Unlike MUSCLE_FIND, this is always reliable |
224| to determine whether KEY has a value. |
225`----------------------------------------------------------------------------*/
226
227char const *
228muscle_find_const (char const *key)
229{
230 muscle_entry probe;
231 muscle_entry *result = NULL;
232
233 probe.key = key;
234 result = hash_lookup (muscle_table, &probe);
235 if (result)
236 return result->value;
237 return NULL;
238}
239
240
4502eadc
JD
241/*----------------------------------------------------------------------------.
242| Find the value of muscle KEY. Abort if muscle_insert was invoked more |
243| recently than muscle_grow for KEY since muscle_find can't return a |
244| char const *. |
245`----------------------------------------------------------------------------*/
ae7453f2 246
ff5150d9 247char *
7eb8a0bc 248muscle_find (char const *key)
f753cd62 249{
8322e8f5
PE
250 muscle_entry probe;
251 muscle_entry *result = NULL;
e9bca3ad 252
ae7453f2
AD
253 probe.key = key;
254 result = hash_lookup (muscle_table, &probe);
4502eadc
JD
255 if (result)
256 {
257 aver (result->value == result->storage);
258 return result->storage;
259 }
260 return NULL;
f753cd62 261}
be2a1a68
AD
262
263
9611cfa2
JD
264void
265muscle_boundary_grow (char const *key, boundary bound)
266{
267 char *extension;
268 MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file);
269 obstack_1grow (&muscle_obstack, ':');
270 obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
271 obstack_1grow (&muscle_obstack, '.');
272 obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
273 obstack_1grow (&muscle_obstack, '\0');
274 extension = obstack_finish (&muscle_obstack);
275 muscle_grow (key, extension, "");
276 obstack_free (&muscle_obstack, extension);
277}
278
279void
280muscle_location_grow (char const *key, location loc)
281{
282 muscle_grow (key, "[[", "");
283 muscle_boundary_grow (key, loc.start);
284 muscle_grow (key, "]], [[", "");
285 muscle_boundary_grow (key, loc.end);
286 muscle_grow (key, "]]", "");
287}
288
f124d423
JD
289#define MUSCLE_COMMON_DECODE(Value) \
290 case '$': \
291 aver (*++(Value) == ']'); \
292 aver (*++(Value) == '['); \
293 obstack_sgrow (&muscle_obstack, "$"); \
294 break; \
295 case '@': \
296 switch (*++(Value)) \
297 { \
298 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
299 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
300 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
301 default: aver (false); break; \
302 } \
303 break; \
304 default: \
305 obstack_1grow (&muscle_obstack, *(Value)); \
306 break;
307
308/* Reverse of MUSCLE_OBSTACK_SGROW. */
309static char *
310muscle_string_decode (char const *key)
311{
312 char const *value;
313 char *value_decoded;
314 char *result;
315
316 value = muscle_find_const (key);
317 if (!value)
318 return NULL;
319 do {
320 switch (*value)
321 {
322 MUSCLE_COMMON_DECODE (value)
323 case '[':
324 case ']':
325 aver (false);
326 break;
327 }
328 } while (*value++);
329 value_decoded = obstack_finish (&muscle_obstack);
330 result = xstrdup (value_decoded);
331 obstack_free (&muscle_obstack, value_decoded);
332 return result;
333}
334
9611cfa2
JD
335/* Reverse of muscle_location_grow. */
336static location
337muscle_location_decode (char const *key)
338{
339 location loc;
340 char const *value = muscle_find_const (key);
341 aver (value);
342 aver (*value == '[');
343 aver (*++value == '[');
344 while (*++value)
345 switch (*value)
346 {
f124d423 347 MUSCLE_COMMON_DECODE (value)
9611cfa2
JD
348 case '[':
349 aver (false);
350 break;
351 case ']':
352 {
353 char *boundary_str;
354 aver (*++value == ']');
355 obstack_1grow (&muscle_obstack, '\0');
356 boundary_str = obstack_finish (&muscle_obstack);
357 switch (*++value)
358 {
359 case ',':
360 boundary_set_from_string (&loc.start, boundary_str);
361 obstack_free (&muscle_obstack, boundary_str);
362 aver (*++value == ' ');
363 aver (*++value == '[');
364 aver (*++value == '[');
365 break;
366 case '\0':
367 boundary_set_from_string (&loc.end, boundary_str);
368 obstack_free (&muscle_obstack, boundary_str);
369 return loc;
370 break;
371 default:
372 aver (false);
373 break;
374 }
375 }
376 break;
9611cfa2
JD
377 }
378 aver (false);
379 return loc;
380}
381
382void
383muscle_user_name_list_grow (char const *key, char const *user_name,
384 location loc)
385{
386 muscle_grow (key, "[[[[", ",");
387 muscle_grow (key, user_name, "");
388 muscle_grow (key, "]], ", "");
389 muscle_location_grow (key, loc);
390 muscle_grow (key, "]]", "");
391}
392
393#define MUSCLE_USER_NAME_CONVERT(NAME, PREFIX, USER_NAME, SUFFIX) \
394do { \
395 char *tmp; \
396 size_t length = strlen ((USER_NAME)); \
397 tmp = xmalloc (sizeof (PREFIX) - 1 + length + sizeof (SUFFIX)); \
398 strcpy (tmp, (PREFIX)); \
399 strcpy (tmp + sizeof (PREFIX) - 1, (USER_NAME)); \
400 strcpy (tmp + sizeof (PREFIX) - 1 + length, (SUFFIX)); \
401 (NAME) = uniqstr_new (tmp); \
402 free (tmp); \
403} while (0)
404
405void
406muscle_percent_define_insert (char const *variable, location variable_loc,
407 char const *value)
408{
409 char const *name;
410 char const *loc_name;
35b8730d 411 char const *syncline_name;
9611cfa2
JD
412
413 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
414 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
415 MUSCLE_USER_NAME_CONVERT (syncline_name,
416 "percent_define_syncline(", variable, ")");
9611cfa2
JD
417
418 if (muscle_find_const (name))
419 {
420 warn_at (variable_loc, _("%s `%s' redefined"),
421 "%define variable", variable);
35b8730d
JD
422 warn_at (muscle_percent_define_get_loc (variable),
423 _("previous definition"));
9611cfa2
JD
424 }
425 MUSCLE_INSERT_STRING (name, value);
426
427 muscle_insert (loc_name, "");
428 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
429 muscle_insert (syncline_name, "");
430 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
431 muscle_user_name_list_grow ("percent_define_user_variables", variable,
432 variable_loc);
433}
434
f124d423
JD
435char *
436muscle_percent_define_get (char const *variable)
437{
438 char const *name;
439 char const *usage_name;
440 char *value;
441
442 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
443 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
444 variable, ")");
445
446 muscle_insert (usage_name, "");
447 value = muscle_string_decode (name);
448 if (!value)
449 value = xstrdup ("");
450 return value;
451}
452
35b8730d
JD
453location
454muscle_percent_define_get_loc (char const *variable)
455{
456 char const *loc_name;
457 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
458 if (!muscle_find_const (loc_name))
459 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_loc"),
460 variable);
461 return muscle_location_decode (loc_name);
462}
463
464char const *
465muscle_percent_define_get_syncline (char const *variable)
466{
467 char const *syncline_name;
468 char const *syncline;
469 MUSCLE_USER_NAME_CONVERT (syncline_name,
470 "percent_define_syncline(", variable, ")");
471 syncline = muscle_find_const (syncline_name);
472 if (!syncline)
473 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_syncline"),
474 variable);
475 return syncline;
476}
477
f124d423
JD
478bool
479muscle_percent_define_ifdef (char const *variable)
480{
481 char const *name;
482 char const *usage_name;
483 char const *value;
484
485 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
486 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
487 variable, ")");
488
489 value = muscle_find_const (name);
490 if (value)
491 {
492 muscle_insert (usage_name, "");
493 return true;
494 }
495
496 return false;
497}
498
9611cfa2
JD
499bool
500muscle_percent_define_flag_if (char const *variable)
501{
cbd50549 502 char const *invalid_boolean_name;
9611cfa2
JD
503 bool result = false;
504
cbd50549
JD
505 MUSCLE_USER_NAME_CONVERT (invalid_boolean_name,
506 "percent_define_invalid_boolean(", variable, ")");
9611cfa2 507
f124d423 508 if (muscle_percent_define_ifdef (variable))
9611cfa2 509 {
f124d423 510 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
511 if (value[0] == '\0' || 0 == strcmp (value, "true"))
512 result = true;
513 else if (0 == strcmp (value, "false"))
514 result = false;
cbd50549
JD
515 else if (!muscle_find_const (invalid_boolean_name))
516 {
517 muscle_insert (invalid_boolean_name, "");
35b8730d 518 complain_at(muscle_percent_define_get_loc (variable),
922bdd7f 519 _("invalid value for %%define Boolean variable `%s'"),
cbd50549
JD
520 variable);
521 }
f124d423 522 free (value);
9611cfa2
JD
523 }
524 else
525 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
526 variable);
527
9611cfa2
JD
528 return result;
529}
530
531void
532muscle_percent_define_default (char const *variable, char const *value)
533{
534 char const *name;
535 char const *loc_name;
35b8730d 536 char const *syncline_name;
9611cfa2
JD
537 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
538 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
539 MUSCLE_USER_NAME_CONVERT (syncline_name,
540 "percent_define_syncline(", variable, ")");
9611cfa2
JD
541 if (!muscle_find_const (name))
542 {
543 location loc;
544 MUSCLE_INSERT_STRING (name, value);
580c075d
JD
545 loc.start.file = loc.end.file = "<default value>";
546 loc.start.line = loc.end.line = -1;
547 loc.start.column = loc.end.column = -1;
9611cfa2
JD
548 muscle_insert (loc_name, "");
549 muscle_location_grow (loc_name, loc);
35b8730d 550 muscle_insert (syncline_name, "");
9611cfa2
JD
551 }
552}
553
f124d423 554void
b1a81613 555muscle_percent_define_check_values (char const * const *values)
f124d423 556{
b1a81613
JD
557 for (; *values; ++values)
558 {
559 char const *variable = *values;
560 char const *name;
b1a81613
JD
561 char *value;
562
563 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
b1a81613
JD
564
565 value = muscle_string_decode (name);
566 if (value)
567 {
568 bool valid = false;
569 for (++values; *values; ++values)
570 {
571 if (0 == strcmp (value, *values))
572 {
573 valid = true;
574 while (*values)
575 ++values;
576 break;
577 }
578 }
579 if (!valid)
35b8730d 580 complain_at(muscle_percent_define_get_loc (variable),
b1a81613
JD
581 _("invalid value for %%define variable `%s': `%s'"),
582 variable, value);
583 free (value);
584 }
585 else
586 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_check_values"),
587 variable);
588 }
f124d423
JD
589}
590
9611cfa2
JD
591void
592muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
593 char const *code, location code_loc)
594{
595 char const *name;
596 MUSCLE_USER_NAME_CONVERT (name, "percent_code(", qualifier, ")");
597 muscle_code_grow (name, code, code_loc);
598 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
599 qualifier_loc);
600}
601
602
ae7453f2
AD
603/*------------------------------------------------.
604| Output the definition of ENTRY as a m4_define. |
605`------------------------------------------------*/
be2a1a68 606
e00b6826 607static inline bool
8322e8f5 608muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
609{
610 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 611 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
612 return true;
613}
614
615static bool
616muscle_m4_output_processor (void *entry, void *out)
617{
618 return muscle_m4_output (entry, out);
be2a1a68
AD
619}
620
621
ae7453f2
AD
622/*----------------------------------------------------------------.
623| Output the definition of all the current muscles into a list of |
624| m4_defines. |
625`----------------------------------------------------------------*/
be2a1a68
AD
626
627void
628muscles_m4_output (FILE *out)
629{
e00b6826 630 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 631}