]> git.saurik.com Git - bison.git/blame - src/muscle_tab.c
Convert underscores to dashes in some %define variable names.
[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
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{
812775a0 406 char *variable_tr = NULL;
9611cfa2
JD
407 char const *name;
408 char const *loc_name;
35b8730d 409 char const *syncline_name;
9611cfa2 410
812775a0
JD
411 /* Permit certain names with underscores for backward compatibility. */
412 if (0 == strcmp (variable, "api.push_pull")
413 || 0 == strcmp (variable, "lr.keep_unreachable_states"))
414 {
415 variable_tr = strdup (variable);
416 tr (variable_tr, '_', '-');
417 variable = variable_tr;
418 }
419
9611cfa2
JD
420 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
421 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
422 MUSCLE_USER_NAME_CONVERT (syncline_name,
423 "percent_define_syncline(", variable, ")");
9611cfa2
JD
424
425 if (muscle_find_const (name))
426 {
427 warn_at (variable_loc, _("%s `%s' redefined"),
428 "%define variable", variable);
35b8730d
JD
429 warn_at (muscle_percent_define_get_loc (variable),
430 _("previous definition"));
9611cfa2
JD
431 }
432 MUSCLE_INSERT_STRING (name, value);
433
434 muscle_insert (loc_name, "");
435 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
436 muscle_insert (syncline_name, "");
437 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
438 muscle_user_name_list_grow ("percent_define_user_variables", variable,
439 variable_loc);
812775a0
JD
440
441 free (variable_tr);
9611cfa2
JD
442}
443
f124d423
JD
444char *
445muscle_percent_define_get (char const *variable)
446{
447 char const *name;
448 char const *usage_name;
449 char *value;
450
451 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
452 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
453 variable, ")");
454
455 muscle_insert (usage_name, "");
456 value = muscle_string_decode (name);
457 if (!value)
458 value = xstrdup ("");
459 return value;
460}
461
35b8730d
JD
462location
463muscle_percent_define_get_loc (char const *variable)
464{
465 char const *loc_name;
466 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
467 if (!muscle_find_const (loc_name))
468 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_loc"),
469 variable);
470 return muscle_location_decode (loc_name);
471}
472
473char const *
474muscle_percent_define_get_syncline (char const *variable)
475{
476 char const *syncline_name;
477 char const *syncline;
478 MUSCLE_USER_NAME_CONVERT (syncline_name,
479 "percent_define_syncline(", variable, ")");
480 syncline = muscle_find_const (syncline_name);
481 if (!syncline)
482 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_syncline"),
483 variable);
484 return syncline;
485}
486
f124d423
JD
487bool
488muscle_percent_define_ifdef (char const *variable)
489{
490 char const *name;
491 char const *usage_name;
492 char const *value;
493
494 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
495 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
496 variable, ")");
497
498 value = muscle_find_const (name);
499 if (value)
500 {
501 muscle_insert (usage_name, "");
502 return true;
503 }
504
505 return false;
506}
507
9611cfa2
JD
508bool
509muscle_percent_define_flag_if (char const *variable)
510{
cbd50549 511 char const *invalid_boolean_name;
9611cfa2
JD
512 bool result = false;
513
cbd50549
JD
514 MUSCLE_USER_NAME_CONVERT (invalid_boolean_name,
515 "percent_define_invalid_boolean(", variable, ")");
9611cfa2 516
f124d423 517 if (muscle_percent_define_ifdef (variable))
9611cfa2 518 {
f124d423 519 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
520 if (value[0] == '\0' || 0 == strcmp (value, "true"))
521 result = true;
522 else if (0 == strcmp (value, "false"))
523 result = false;
cbd50549
JD
524 else if (!muscle_find_const (invalid_boolean_name))
525 {
526 muscle_insert (invalid_boolean_name, "");
35b8730d 527 complain_at(muscle_percent_define_get_loc (variable),
922bdd7f 528 _("invalid value for %%define Boolean variable `%s'"),
cbd50549
JD
529 variable);
530 }
f124d423 531 free (value);
9611cfa2
JD
532 }
533 else
534 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
535 variable);
536
9611cfa2
JD
537 return result;
538}
539
540void
541muscle_percent_define_default (char const *variable, char const *value)
542{
543 char const *name;
544 char const *loc_name;
35b8730d 545 char const *syncline_name;
9611cfa2
JD
546 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
547 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
548 MUSCLE_USER_NAME_CONVERT (syncline_name,
549 "percent_define_syncline(", variable, ")");
9611cfa2
JD
550 if (!muscle_find_const (name))
551 {
552 location loc;
553 MUSCLE_INSERT_STRING (name, value);
580c075d
JD
554 loc.start.file = loc.end.file = "<default value>";
555 loc.start.line = loc.end.line = -1;
556 loc.start.column = loc.end.column = -1;
9611cfa2
JD
557 muscle_insert (loc_name, "");
558 muscle_location_grow (loc_name, loc);
35b8730d 559 muscle_insert (syncline_name, "");
9611cfa2
JD
560 }
561}
562
f124d423 563void
b1a81613 564muscle_percent_define_check_values (char const * const *values)
f124d423 565{
b1a81613
JD
566 for (; *values; ++values)
567 {
25029e16 568 char const * const *variablep = values;
b1a81613 569 char const *name;
b1a81613
JD
570 char *value;
571
25029e16 572 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", *variablep, ")");
b1a81613
JD
573
574 value = muscle_string_decode (name);
575 if (value)
576 {
b1a81613
JD
577 for (++values; *values; ++values)
578 {
579 if (0 == strcmp (value, *values))
25029e16
JD
580 break;
581 }
582 if (!*values)
583 {
584 location loc = muscle_percent_define_get_loc (*variablep);
585 complain_at(loc,
586 _("invalid value for %%define variable `%s': `%s'"),
587 *variablep, value);
588 for (values = variablep + 1; *values; ++values)
589 complain_at (loc, _("accepted value: `%s'"), *values);
590 }
591 else
592 {
593 while (*values)
594 ++values;
b1a81613 595 }
b1a81613
JD
596 free (value);
597 }
598 else
25029e16
JD
599 fatal(_("undefined %%define variable `%s' passed to"
600 " muscle_percent_define_check_values"),
601 *variablep);
b1a81613 602 }
f124d423
JD
603}
604
9611cfa2
JD
605void
606muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
607 char const *code, location code_loc)
608{
609 char const *name;
610 MUSCLE_USER_NAME_CONVERT (name, "percent_code(", qualifier, ")");
611 muscle_code_grow (name, code, code_loc);
612 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
613 qualifier_loc);
614}
615
616
ae7453f2
AD
617/*------------------------------------------------.
618| Output the definition of ENTRY as a m4_define. |
619`------------------------------------------------*/
be2a1a68 620
e00b6826 621static inline bool
8322e8f5 622muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
623{
624 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 625 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
626 return true;
627}
628
629static bool
630muscle_m4_output_processor (void *entry, void *out)
631{
632 return muscle_m4_output (entry, out);
be2a1a68
AD
633}
634
635
ae7453f2
AD
636/*----------------------------------------------------------------.
637| Output the definition of all the current muscles into a list of |
638| m4_defines. |
639`----------------------------------------------------------------*/
be2a1a68
AD
640
641void
642muscles_m4_output (FILE *out)
643{
e00b6826 644 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 645}