]> git.saurik.com Git - bison.git/blame - src/muscle-tab.c
tests: restore the tests on -Werror
[bison.git] / src / muscle-tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
c932d613 3 Copyright (C) 2001-2012 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>
8322e8f5 24
9611cfa2 25#include "complain.h"
f753cd62 26#include "files.h"
f508cb0a 27#include "getargs.h"
4c787a31
AD
28#include "muscle-tab.h"
29#include "quote.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);
f753cd62
MA
87}
88
592e8d4d
AD
89
90/*------------------------------------------------------------.
91| Free all the memory consumed by the muscle machinery only. |
92`------------------------------------------------------------*/
93
94void
95muscle_free (void)
96{
97 hash_free (muscle_table);
98 obstack_free (&muscle_obstack, NULL);
99}
100
101
102
ae7453f2
AD
103/*------------------------------------------------------------.
104| Insert (KEY, VALUE). If KEY already existed, overwrite the |
105| previous value. |
106`------------------------------------------------------------*/
107
a870c567 108void
eb095650 109muscle_insert (char const *key, char const *value)
f753cd62 110{
8322e8f5 111 muscle_entry probe;
da2a7671 112 muscle_entry *entry;
e9bca3ad 113
ae7453f2
AD
114 probe.key = key;
115 entry = hash_lookup (muscle_table, &probe);
beda758b
AD
116
117 if (!entry)
118 {
119 /* First insertion in the hash. */
da2a7671 120 entry = xmalloc (sizeof *entry);
beda758b 121 entry->key = key;
75c7a52a
AD
122 if (!hash_insert (muscle_table, entry))
123 xalloc_die ();
beda758b 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 151 entry->key = key;
75c7a52a
AD
152 if (!hash_insert (muscle_table, entry))
153 xalloc_die ();
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;
aaf63e45 180 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
0601c3bf
AD
181 obstack_quote (&muscle_obstack,
182 quotearg_style (c_quoting_style, loc.start.file));
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;
0601c3bf
AD
208 obstack_sgrow (&muscle_obstack, "[");
209 obstack_quote (&muscle_obstack, a1);
210 obstack_sgrow (&muscle_obstack, ", ");
211 obstack_quote (&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
e5878229
AD
262/* In the format `file_name:line.column', append BOUND to MUSCLE. Use
263 digraphs for special characters in the file name. */
264
265static void
9611cfa2
JD
266muscle_boundary_grow (char const *key, boundary bound)
267{
268 char *extension;
eea7239a 269 obstack_sgrow (&muscle_obstack, "[[");
13b712d7 270 obstack_escape (&muscle_obstack, bound.file);
eea7239a 271 obstack_1grow (&muscle_obstack, ':');
aaf63e45 272 obstack_printf (&muscle_obstack, "%d", bound.line);
eea7239a 273 obstack_1grow (&muscle_obstack, '.');
aaf63e45 274 obstack_printf (&muscle_obstack, "%d", bound.column);
eea7239a
AD
275 obstack_sgrow (&muscle_obstack, "]]");
276 obstack_1grow (&muscle_obstack, '\0');
9611cfa2
JD
277 extension = obstack_finish (&muscle_obstack);
278 muscle_grow (key, extension, "");
279 obstack_free (&muscle_obstack, extension);
280}
281
e5878229
AD
282
283/* In the format `[[file_name:line.column]], [[file_name:line.column]]',
284 append LOC to MUSCLE. Use digraphs for special characters in each
285 file name. */
286
287static void
9611cfa2
JD
288muscle_location_grow (char const *key, location loc)
289{
9611cfa2 290 muscle_boundary_grow (key, loc.start);
eea7239a 291 muscle_grow (key, "", ", ");
9611cfa2 292 muscle_boundary_grow (key, loc.end);
9611cfa2
JD
293}
294
c1cc91bd 295#define COMMON_DECODE(Value) \
9b858541
AD
296 case '$': \
297 aver (*++(Value) == ']'); \
298 aver (*++(Value) == '['); \
299 obstack_sgrow (&muscle_obstack, "$"); \
300 break; \
301 case '@': \
302 switch (*++(Value)) \
303 { \
304 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
305 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
306 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
307 default: aver (false); break; \
308 } \
309 break; \
310 default: \
311 obstack_1grow (&muscle_obstack, *(Value)); \
f124d423
JD
312 break;
313
c1cc91bd 314/* Reverse of obstack_escape. */
f124d423 315static char *
c1cc91bd 316string_decode (char const *key)
f124d423
JD
317{
318 char const *value;
319 char *value_decoded;
320 char *result;
321
322 value = muscle_find_const (key);
323 if (!value)
324 return NULL;
325 do {
326 switch (*value)
327 {
c1cc91bd 328 COMMON_DECODE (value)
f124d423
JD
329 case '[':
330 case ']':
331 aver (false);
332 break;
333 }
334 } while (*value++);
335 value_decoded = obstack_finish (&muscle_obstack);
336 result = xstrdup (value_decoded);
337 obstack_free (&muscle_obstack, value_decoded);
338 return result;
339}
340
9611cfa2
JD
341/* Reverse of muscle_location_grow. */
342static location
c1cc91bd 343location_decode (char const *key)
9611cfa2
JD
344{
345 location loc;
346 char const *value = muscle_find_const (key);
347 aver (value);
348 aver (*value == '[');
349 aver (*++value == '[');
350 while (*++value)
351 switch (*value)
352 {
c1cc91bd 353 COMMON_DECODE (value)
9611cfa2
JD
354 case '[':
355 aver (false);
356 break;
357 case ']':
358 {
359 char *boundary_str;
360 aver (*++value == ']');
361 obstack_1grow (&muscle_obstack, '\0');
362 boundary_str = obstack_finish (&muscle_obstack);
363 switch (*++value)
364 {
365 case ',':
366 boundary_set_from_string (&loc.start, boundary_str);
367 obstack_free (&muscle_obstack, boundary_str);
368 aver (*++value == ' ');
369 aver (*++value == '[');
370 aver (*++value == '[');
371 break;
372 case '\0':
373 boundary_set_from_string (&loc.end, boundary_str);
374 obstack_free (&muscle_obstack, boundary_str);
375 return loc;
376 break;
377 default:
378 aver (false);
379 break;
380 }
381 }
382 break;
9611cfa2
JD
383 }
384 aver (false);
385 return loc;
386}
387
388void
389muscle_user_name_list_grow (char const *key, char const *user_name,
390 location loc)
391{
392 muscle_grow (key, "[[[[", ",");
393 muscle_grow (key, user_name, "");
394 muscle_grow (key, "]], ", "");
395 muscle_location_grow (key, loc);
396 muscle_grow (key, "]]", "");
397}
398
9611cfa2
JD
399void
400muscle_percent_define_insert (char const *variable, location variable_loc,
34d41938
JD
401 char const *value,
402 muscle_percent_define_how how)
9611cfa2 403{
812775a0 404 char *variable_tr = NULL;
9611cfa2
JD
405 char const *name;
406 char const *loc_name;
35b8730d 407 char const *syncline_name;
34d41938 408 char const *how_name;
9611cfa2 409
812775a0
JD
410 /* Permit certain names with underscores for backward compatibility. */
411 if (0 == strcmp (variable, "api.push_pull")
412 || 0 == strcmp (variable, "lr.keep_unreachable_states"))
413 {
414 variable_tr = strdup (variable);
415 tr (variable_tr, '_', '-');
416 variable = variable_tr;
417 }
418
0ab402b4
JD
419 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
420 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
421 syncline_name =
422 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
423 how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
9611cfa2 424
34d41938
JD
425 /* Command-line options are processed before the grammar file. */
426 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
427 && muscle_find_const (name))
9611cfa2 428 {
34d41938
JD
429 muscle_percent_define_how how_old =
430 atoi (muscle_find_const (how_name));
431 if (how_old == MUSCLE_PERCENT_DEFINE_F)
432 {
433 free (variable_tr);
434 return;
435 }
4c787a31
AD
436 complain_at (variable_loc, _("%%define variable %s redefined"),
437 quote (variable));
e3a33f7c 438 complain_at (muscle_percent_define_get_loc (variable),
34d41938 439 _("previous definition"));
9611cfa2 440 }
9611cfa2 441
34d41938 442 MUSCLE_INSERT_STRING (name, value);
9611cfa2
JD
443 muscle_insert (loc_name, "");
444 muscle_location_grow (loc_name, variable_loc);
35b8730d
JD
445 muscle_insert (syncline_name, "");
446 muscle_syncline_grow (syncline_name, variable_loc);
9611cfa2
JD
447 muscle_user_name_list_grow ("percent_define_user_variables", variable,
448 variable_loc);
34d41938 449 MUSCLE_INSERT_INT (how_name, how);
812775a0
JD
450
451 free (variable_tr);
9611cfa2
JD
452}
453
f124d423
JD
454char *
455muscle_percent_define_get (char const *variable)
456{
457 char const *name;
458 char const *usage_name;
459 char *value;
460
0ab402b4
JD
461 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
462 usage_name = UNIQSTR_CONCAT ("percent_define_bison_variables(",
463 variable, ")");
f124d423
JD
464
465 muscle_insert (usage_name, "");
c1cc91bd 466 value = string_decode (name);
f124d423
JD
467 if (!value)
468 value = xstrdup ("");
469 return value;
470}
471
35b8730d
JD
472location
473muscle_percent_define_get_loc (char const *variable)
474{
475 char const *loc_name;
0ab402b4 476 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
35b8730d 477 if (!muscle_find_const (loc_name))
4c787a31
AD
478 fatal(_("%s: undefined %%define variable %s"),
479 "muscle_percent_define_get_loc", quote (variable));
c1cc91bd 480 return location_decode (loc_name);
35b8730d
JD
481}
482
483char const *
484muscle_percent_define_get_syncline (char const *variable)
485{
486 char const *syncline_name;
487 char const *syncline;
0ab402b4
JD
488 syncline_name =
489 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
35b8730d
JD
490 syncline = muscle_find_const (syncline_name);
491 if (!syncline)
4c787a31
AD
492 fatal(_("%s: undefined %%define variable %s"),
493 "muscle_percent_define_get_syncline", quote (variable));
35b8730d
JD
494 return syncline;
495}
496
f124d423
JD
497bool
498muscle_percent_define_ifdef (char const *variable)
499{
500 char const *name;
501 char const *usage_name;
502 char const *value;
503
0ab402b4
JD
504 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
505 usage_name =
506 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
f124d423
JD
507
508 value = muscle_find_const (name);
509 if (value)
510 {
511 muscle_insert (usage_name, "");
512 return true;
513 }
514
515 return false;
516}
517
9611cfa2
JD
518bool
519muscle_percent_define_flag_if (char const *variable)
520{
cbd50549 521 char const *invalid_boolean_name;
9611cfa2
JD
522 bool result = false;
523
0ab402b4
JD
524 invalid_boolean_name =
525 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
9611cfa2 526
f124d423 527 if (muscle_percent_define_ifdef (variable))
9611cfa2 528 {
f124d423 529 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
530 if (value[0] == '\0' || 0 == strcmp (value, "true"))
531 result = true;
532 else if (0 == strcmp (value, "false"))
533 result = false;
cbd50549
JD
534 else if (!muscle_find_const (invalid_boolean_name))
535 {
536 muscle_insert (invalid_boolean_name, "");
35b8730d 537 complain_at(muscle_percent_define_get_loc (variable),
4c787a31
AD
538 _("invalid value for %%define Boolean variable %s"),
539 quote (variable));
cbd50549 540 }
f124d423 541 free (value);
9611cfa2
JD
542 }
543 else
4c787a31
AD
544 fatal(_("%s: undefined %%define variable %s"),
545 "muscle_percent_define_flag", quote (variable));
9611cfa2 546
9611cfa2
JD
547 return result;
548}
549
550void
551muscle_percent_define_default (char const *variable, char const *value)
552{
553 char const *name;
554 char const *loc_name;
35b8730d 555 char const *syncline_name;
0ab402b4
JD
556 name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
557 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
558 syncline_name =
559 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
9611cfa2
JD
560 if (!muscle_find_const (name))
561 {
562 location loc;
563 MUSCLE_INSERT_STRING (name, value);
580c075d
JD
564 loc.start.file = loc.end.file = "<default value>";
565 loc.start.line = loc.end.line = -1;
566 loc.start.column = loc.end.column = -1;
9611cfa2
JD
567 muscle_insert (loc_name, "");
568 muscle_location_grow (loc_name, loc);
35b8730d 569 muscle_insert (syncline_name, "");
9611cfa2
JD
570 }
571}
572
f124d423 573void
b1a81613 574muscle_percent_define_check_values (char const * const *values)
f124d423 575{
b1a81613
JD
576 for (; *values; ++values)
577 {
25029e16 578 char const * const *variablep = values;
b1a81613 579 char const *name;
b1a81613
JD
580 char *value;
581
0ab402b4 582 name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
b1a81613 583
c1cc91bd 584 value = string_decode (name);
b1a81613
JD
585 if (value)
586 {
b1a81613
JD
587 for (++values; *values; ++values)
588 {
589 if (0 == strcmp (value, *values))
25029e16
JD
590 break;
591 }
592 if (!*values)
593 {
594 location loc = muscle_percent_define_get_loc (*variablep);
595 complain_at(loc,
4c787a31
AD
596 _("invalid value for %%define variable %s: %s"),
597 quote (*variablep), quote_n (1, value));
25029e16 598 for (values = variablep + 1; *values; ++values)
4c787a31 599 complain_at (loc, _("accepted value: %s"), quote (*values));
25029e16
JD
600 }
601 else
602 {
603 while (*values)
604 ++values;
b1a81613 605 }
b1a81613
JD
606 free (value);
607 }
608 else
4c787a31
AD
609 fatal (_("%s: undefined %%define variable %s"),
610 "muscle_percent_define_check_values", quote (*variablep));
b1a81613 611 }
f124d423
JD
612}
613
9611cfa2
JD
614void
615muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
616 char const *code, location code_loc)
617{
618 char const *name;
0ab402b4 619 name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
9611cfa2
JD
620 muscle_code_grow (name, code, code_loc);
621 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
622 qualifier_loc);
623}
624
625
ae7453f2
AD
626/*------------------------------------------------.
627| Output the definition of ENTRY as a m4_define. |
628`------------------------------------------------*/
be2a1a68 629
e00b6826 630static inline bool
8322e8f5 631muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
632{
633 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 634 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
635 return true;
636}
637
638static bool
639muscle_m4_output_processor (void *entry, void *out)
640{
641 return muscle_m4_output (entry, out);
be2a1a68
AD
642}
643
644
ae7453f2
AD
645/*----------------------------------------------------------------.
646| Output the definition of all the current muscles into a list of |
647| m4_defines. |
648`----------------------------------------------------------------*/
be2a1a68
AD
649
650void
651muscles_m4_output (FILE *out)
652{
e00b6826 653 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 654}