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