]> git.saurik.com Git - bison.git/blame - src/muscle_tab.c
tests: link lib/libbison.a for gnulib.
[bison.git] / src / muscle_tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
219c26ea 3 Copyright (C) 2001-2007, 2009-2010 Free Software Foundation, Inc.
f753cd62
MA
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
f16b0819 7 This program is free software: you can redistribute it and/or modify
f753cd62 8 it under the terms of the GNU General Public License as published by
f16b0819
PE
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
f753cd62 11
f16b0819 12 This program is distributed in the hope that it will be useful,
f753cd62
MA
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
f16b0819 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
f753cd62 19
2cec9080 20#include <config.h>
f753cd62 21#include "system.h"
8322e8f5
PE
22
23#include <hash.h>
24#include <quotearg.h>
25
9611cfa2 26#include "complain.h"
f753cd62
MA
27#include "files.h"
28#include "muscle_tab.h"
f508cb0a 29#include "getargs.h"
f753cd62 30
eb095650
PE
31/* A key-value pair, along with storage that can be reclaimed when
32 this pair is no longer needed. */
8322e8f5
PE
33typedef struct
34{
eb095650
PE
35 char const *key;
36 char const *value;
37 char *storage;
8322e8f5 38} muscle_entry;
592e8d4d
AD
39
40/* An obstack used to create some entries. */
41struct obstack muscle_obstack;
42
beda758b
AD
43/* Initial capacity of muscles hash table. */
44#define HT_INITIAL_CAPACITY 257
f753cd62 45
04098407 46static struct hash_table *muscle_table = NULL;
f753cd62 47
beda758b
AD
48static bool
49hash_compare_muscles (void const *x, void const *y)
f753cd62 50{
8322e8f5
PE
51 muscle_entry const *m1 = x;
52 muscle_entry const *m2 = y;
5dd5fd4a 53 return strcmp (m1->key, m2->key) == 0;
f753cd62
MA
54}
55
233a88ad
PE
56static size_t
57hash_muscle (const void *x, size_t tablesize)
f753cd62 58{
8322e8f5 59 muscle_entry const *m = x;
beda758b 60 return hash_string (m->key, tablesize);
f753cd62
MA
61}
62
592e8d4d
AD
63/*-----------------------------------------------------------------.
64| Create the MUSCLE_TABLE, and initialize it with default values. |
65| Also set up the MUSCLE_OBSTACK. |
66`-----------------------------------------------------------------*/
67
eb095650
PE
68static void
69muscle_entry_free (void *entry)
70{
71 muscle_entry *mentry = entry;
72 free (mentry->storage);
73 free (mentry);
74}
75
f753cd62
MA
76void
77muscle_init (void)
78{
ae7453f2
AD
79 /* Initialize the muscle obstack. */
80 obstack_init (&muscle_obstack);
81
beda758b 82 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
eb095650 83 hash_compare_muscles, muscle_entry_free);
f753cd62
MA
84
85 /* Version and input file. */
ae7453f2 86 MUSCLE_INSERT_STRING ("version", VERSION);
48b16bbc 87 MUSCLE_INSERT_C_STRING ("file_name", grammar_file);
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;
914e713d
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;
914e713d
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,
406 char const *value)
407{
408 char const *name;
409 char const *loc_name;
35b8730d 410 char const *syncline_name;
9611cfa2
JD
411
412 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
413 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
414 MUSCLE_USER_NAME_CONVERT (syncline_name,
415 "percent_define_syncline(", variable, ")");
9611cfa2
JD
416
417 if (muscle_find_const (name))
418 {
419 warn_at (variable_loc, _("%s `%s' redefined"),
420 "%define variable", variable);
35b8730d
JD
421 warn_at (muscle_percent_define_get_loc (variable),
422 _("previous definition"));
9611cfa2
JD
423 }
424 MUSCLE_INSERT_STRING (name, value);
425
426 muscle_insert (loc_name, "");
427 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
428 muscle_insert (syncline_name, "");
429 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
430 muscle_user_name_list_grow ("percent_define_user_variables", variable,
431 variable_loc);
432}
433
f124d423
JD
434char *
435muscle_percent_define_get (char const *variable)
436{
437 char const *name;
438 char const *usage_name;
439 char *value;
440
441 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
442 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
443 variable, ")");
444
445 muscle_insert (usage_name, "");
446 value = muscle_string_decode (name);
447 if (!value)
448 value = xstrdup ("");
449 return value;
450}
451
35b8730d
JD
452location
453muscle_percent_define_get_loc (char const *variable)
454{
455 char const *loc_name;
456 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
457 if (!muscle_find_const (loc_name))
458 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_loc"),
459 variable);
460 return muscle_location_decode (loc_name);
461}
462
463char const *
464muscle_percent_define_get_syncline (char const *variable)
465{
466 char const *syncline_name;
467 char const *syncline;
468 MUSCLE_USER_NAME_CONVERT (syncline_name,
469 "percent_define_syncline(", variable, ")");
470 syncline = muscle_find_const (syncline_name);
471 if (!syncline)
472 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_get_syncline"),
473 variable);
474 return syncline;
475}
476
f124d423
JD
477bool
478muscle_percent_define_ifdef (char const *variable)
479{
480 char const *name;
481 char const *usage_name;
482 char const *value;
483
484 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
485 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
486 variable, ")");
487
488 value = muscle_find_const (name);
489 if (value)
490 {
491 muscle_insert (usage_name, "");
492 return true;
493 }
494
495 return false;
496}
497
9611cfa2
JD
498bool
499muscle_percent_define_flag_if (char const *variable)
500{
cbd50549 501 char const *invalid_boolean_name;
9611cfa2
JD
502 bool result = false;
503
cbd50549
JD
504 MUSCLE_USER_NAME_CONVERT (invalid_boolean_name,
505 "percent_define_invalid_boolean(", variable, ")");
9611cfa2 506
f124d423 507 if (muscle_percent_define_ifdef (variable))
9611cfa2 508 {
f124d423 509 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
510 if (value[0] == '\0' || 0 == strcmp (value, "true"))
511 result = true;
512 else if (0 == strcmp (value, "false"))
513 result = false;
cbd50549
JD
514 else if (!muscle_find_const (invalid_boolean_name))
515 {
516 muscle_insert (invalid_boolean_name, "");
35b8730d 517 complain_at(muscle_percent_define_get_loc (variable),
922bdd7f 518 _("invalid value for %%define Boolean variable `%s'"),
cbd50549
JD
519 variable);
520 }
f124d423 521 free (value);
9611cfa2
JD
522 }
523 else
524 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
525 variable);
526
9611cfa2
JD
527 return result;
528}
529
530void
531muscle_percent_define_default (char const *variable, char const *value)
532{
533 char const *name;
534 char const *loc_name;
35b8730d 535 char const *syncline_name;
9611cfa2
JD
536 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
537 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
35b8730d
JD
538 MUSCLE_USER_NAME_CONVERT (syncline_name,
539 "percent_define_syncline(", variable, ")");
9611cfa2
JD
540 if (!muscle_find_const (name))
541 {
542 location loc;
543 MUSCLE_INSERT_STRING (name, value);
580c075d
JD
544 loc.start.file = loc.end.file = "<default value>";
545 loc.start.line = loc.end.line = -1;
546 loc.start.column = loc.end.column = -1;
9611cfa2
JD
547 muscle_insert (loc_name, "");
548 muscle_location_grow (loc_name, loc);
35b8730d 549 muscle_insert (syncline_name, "");
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}