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