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