]> git.saurik.com Git - bison.git/blame_incremental - src/muscle-tab.c
grammar: split %union to group together related aspects
[bison.git] / src / muscle-tab.c
... / ...
CommitLineData
1/* Muscle table manager for Bison.
2
3 Copyright (C) 2001-2013 Free Software Foundation, Inc.
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
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
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include <config.h>
21#include "system.h"
22
23#include <hash.h>
24
25#include "complain.h"
26#include "files.h"
27#include "getargs.h"
28#include "muscle-tab.h"
29#include "quote.h"
30
31/* A key-value pair, along with storage that can be reclaimed when
32 this pair is no longer needed. */
33typedef struct
34{
35 char const *key;
36 char const *value;
37 char *storage;
38} muscle_entry;
39
40/* An obstack used to create some entries. */
41struct obstack muscle_obstack;
42
43/* Initial capacity of muscles hash table. */
44#define HT_INITIAL_CAPACITY 257
45
46static struct hash_table *muscle_table = NULL;
47
48static bool
49hash_compare_muscles (void const *x, void const *y)
50{
51 muscle_entry const *m1 = x;
52 muscle_entry const *m2 = y;
53 return STREQ (m1->key, m2->key);
54}
55
56static size_t
57hash_muscle (const void *x, size_t tablesize)
58{
59 muscle_entry const *m = x;
60 return hash_string (m->key, tablesize);
61}
62
63/* Create a fresh muscle name KEY, and insert in the hash table. */
64static void *
65muscle_entry_new (char const *key)
66{
67 muscle_entry *res = xmalloc (sizeof *res);
68 res->key = key;
69 res->value = NULL;
70 res->storage = NULL;
71 if (!hash_insert (muscle_table, res))
72 xalloc_die ();
73 return res;
74}
75
76static void
77muscle_entry_free (void *entry)
78{
79 muscle_entry *mentry = entry;
80 free (mentry->storage);
81 free (mentry);
82}
83
84void
85muscle_init (void)
86{
87 /* Initialize the muscle obstack. */
88 obstack_init (&muscle_obstack);
89
90 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
91 hash_compare_muscles, muscle_entry_free);
92
93 /* Version and input file. */
94 MUSCLE_INSERT_STRING ("version", VERSION);
95}
96
97
98void
99muscle_free (void)
100{
101 hash_free (muscle_table);
102 obstack_free (&muscle_obstack, NULL);
103}
104
105/* Look for the muscle named KEY. Return NULL if does not exist. */
106static
107muscle_entry *
108muscle_lookup (char const *key)
109{
110 muscle_entry probe;
111 probe.key = key;
112 return hash_lookup (muscle_table, &probe);
113}
114
115
116void
117muscle_insert (char const *key, char const *value)
118{
119 muscle_entry *entry = muscle_lookup (key);
120 if (entry)
121 free (entry->storage);
122 else
123 /* First insertion in the hash. */
124 entry = muscle_entry_new (key);
125 entry->value = value;
126 entry->storage = NULL;
127}
128
129
130/*-------------------------------------------------------------------.
131| Append VALUE to the current value of KEY. If KEY did not already |
132| exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
133| associated value. Copy VALUE and SEPARATOR. |
134`-------------------------------------------------------------------*/
135
136void
137muscle_grow (const char *key, const char *val, const char *separator)
138{
139 muscle_entry *entry = muscle_lookup (key);
140
141 if (entry)
142 {
143 /* Grow the current value. */
144 char *new_val;
145 obstack_printf (&muscle_obstack, "%s%s%s", entry->value, separator, val);
146 free (entry->storage);
147 new_val = obstack_finish0 (&muscle_obstack);
148 entry->value = entry->storage = xstrdup (new_val);
149 obstack_free (&muscle_obstack, new_val);
150 }
151 else
152 {
153 /* First insertion in the hash. */
154 entry = muscle_entry_new (key);
155 entry->value = entry->storage = xstrdup (val);
156 }
157}
158
159/*------------------------------------------------------------------.
160| Using muscle_grow, append a synchronization line for the location |
161| LOC to the current value of KEY. |
162`------------------------------------------------------------------*/
163
164static void
165muscle_syncline_grow (char const *key, location loc)
166{
167 char *extension = NULL;
168 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
169 obstack_quote (&muscle_obstack,
170 quotearg_style (c_quoting_style, loc.start.file));
171 obstack_sgrow (&muscle_obstack, ")[");
172 extension = obstack_finish0 (&muscle_obstack);
173 muscle_grow (key, extension, "");
174 obstack_free (&muscle_obstack, extension);
175}
176
177/*------------------------------------------------------------------.
178| Append VALUE to the current value of KEY, using muscle_grow. But |
179| in addition, issue a synchronization line for the location LOC |
180| using muscle_syncline_grow. |
181`------------------------------------------------------------------*/
182
183void
184muscle_code_grow (const char *key, const char *val, location loc)
185{
186 muscle_syncline_grow (key, loc);
187 muscle_grow (key, val, "\n");
188}
189
190
191void
192muscle_pair_list_grow (const char *muscle,
193 const char *a1, const char *a2)
194{
195 char *pair;
196 obstack_sgrow (&muscle_obstack, "[");
197 obstack_quote (&muscle_obstack, a1);
198 obstack_sgrow (&muscle_obstack, ", ");
199 obstack_quote (&muscle_obstack, a2);
200 obstack_sgrow (&muscle_obstack, "]");
201 pair = obstack_finish0 (&muscle_obstack);
202 muscle_grow (muscle, pair, ",\n");
203 obstack_free (&muscle_obstack, pair);
204}
205
206
207char const *
208muscle_find_const (char const *key)
209{
210 muscle_entry *entry = muscle_lookup (key);
211 return entry ? entry->value : NULL;
212}
213
214
215char *
216muscle_find (char const *key)
217{
218 muscle_entry *entry = muscle_lookup (key);
219 if (entry)
220 {
221 aver (entry->value == entry->storage);
222 return entry->storage;
223 }
224 return NULL;
225}
226
227
228/* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
229 digraphs for special characters in the file name. */
230
231static void
232muscle_boundary_grow (char const *key, boundary bound)
233{
234 char *extension;
235 obstack_sgrow (&muscle_obstack, "[[");
236 obstack_escape (&muscle_obstack, bound.file);
237 obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
238 extension = obstack_finish0 (&muscle_obstack);
239 muscle_grow (key, extension, "");
240 obstack_free (&muscle_obstack, extension);
241}
242
243
244/* In the format '[[file_name:line.column]], [[file_name:line.column]]',
245 append LOC to MUSCLE. Use digraphs for special characters in each
246 file name. */
247
248static void
249muscle_location_grow (char const *key, location loc)
250{
251 muscle_boundary_grow (key, loc.start);
252 muscle_grow (key, "", ", ");
253 muscle_boundary_grow (key, loc.end);
254}
255
256#define COMMON_DECODE(Value) \
257 case '$': \
258 aver (*++(Value) == ']'); \
259 aver (*++(Value) == '['); \
260 obstack_sgrow (&muscle_obstack, "$"); \
261 break; \
262 case '@': \
263 switch (*++(Value)) \
264 { \
265 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
266 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
267 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
268 default: aver (false); break; \
269 } \
270 break; \
271 default: \
272 obstack_1grow (&muscle_obstack, *(Value)); \
273 break;
274
275/* Reverse of obstack_escape. */
276static char *
277string_decode (char const *key)
278{
279 char const *value = muscle_find_const (key);
280 char *value_decoded;
281 char *result;
282
283 if (!value)
284 return NULL;
285 do {
286 switch (*value)
287 {
288 COMMON_DECODE (value)
289 case '[':
290 case ']':
291 aver (false);
292 break;
293 }
294 } while (*value++);
295 value_decoded = obstack_finish (&muscle_obstack);
296 result = xstrdup (value_decoded);
297 obstack_free (&muscle_obstack, value_decoded);
298 return result;
299}
300
301/* Reverse of muscle_location_grow. */
302static location
303location_decode (char const *key)
304{
305 location loc;
306 char const *value = muscle_find_const (key);
307 aver (value);
308 aver (*value == '[');
309 aver (*++value == '[');
310 while (*++value)
311 switch (*value)
312 {
313 COMMON_DECODE (value)
314 case '[':
315 aver (false);
316 break;
317 case ']':
318 {
319 char *boundary_str;
320 aver (*++value == ']');
321 boundary_str = obstack_finish0 (&muscle_obstack);
322 switch (*++value)
323 {
324 case ',':
325 boundary_set_from_string (&loc.start, boundary_str);
326 obstack_free (&muscle_obstack, boundary_str);
327 aver (*++value == ' ');
328 aver (*++value == '[');
329 aver (*++value == '[');
330 break;
331 case '\0':
332 boundary_set_from_string (&loc.end, boundary_str);
333 obstack_free (&muscle_obstack, boundary_str);
334 return loc;
335 break;
336 default:
337 aver (false);
338 break;
339 }
340 }
341 break;
342 }
343 aver (false);
344 return loc;
345}
346
347void
348muscle_user_name_list_grow (char const *key, char const *user_name,
349 location loc)
350{
351 muscle_grow (key, "[[[[", ",");
352 muscle_grow (key, user_name, "");
353 muscle_grow (key, "]], ", "");
354 muscle_location_grow (key, loc);
355 muscle_grow (key, "]]", "");
356}
357
358
359/** Return an allocated string that represents the %define directive
360 that performs the assignment.
361
362 @param assignment "VAR", or "VAR=VAL".
363 @param value default value if VAL \a assignment has no '='.
364
365 For instance:
366 "foo", NULL => "%define foo"
367 "foo", "baz" => "%define foo baz"
368 "foo=bar", NULL => "%define foo bar"
369 "foo=bar", "baz" => "%define foo bar"
370 "foo=", NULL => "%define foo"
371 "foo=", "baz" => "%define foo"
372 */
373
374static
375char *
376define_directive (char const *assignment, char const *value)
377{
378 char *eq = strchr (assignment, '=');
379 char const *fmt = !eq && value && *value ? "%%define %s %s" : "%%define %s";
380 char *res = xmalloc (strlen (fmt) + strlen (assignment)
381 + (value ? strlen (value) : 0));
382 sprintf (res, fmt, assignment, value);
383 eq = strchr (res, '=');
384 if (eq)
385 *eq = eq[1] ? ' ' : '\0';
386 return res;
387}
388
389/** If the \a variable name is obsolete, return the name to use,
390 * otherwise \a variable. If the \a value is obsolete, update it too.
391 *
392 * Allocates the returned value. */
393static
394char *
395muscle_percent_variable_update (char const *variable, location variable_loc,
396 char const **value)
397{
398 typedef struct
399 {
400 const char *obsolete;
401 const char *updated;
402 } conversion_type;
403 const conversion_type conversion[] =
404 {
405 { "api.push_pull", "api.push-pull", },
406 { "api.tokens.prefix", "api.token.prefix", },
407 { "lex_symbol", "api.token.constructor", },
408 { "location_type", "api.location.type", },
409 { "lr.default-reductions", "lr.default-reduction", },
410 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", },
411 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", },
412 { "namespace", "api.namespace", },
413 { "stype", "api.value.type", },
414 { "variant=", "api.value.type=variant", },
415 { "variant=true", "api.value.type=variant", },
416 { NULL, NULL, }
417 };
418 conversion_type const *c;
419 for (c = conversion; c->obsolete; ++c)
420 {
421 char const *eq = strchr (c->obsolete, '=');
422 if (eq
423 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
424 && STREQ (eq + 1, *value))
425 : STREQ (c->obsolete, variable))
426 {
427 char *old = define_directive (c->obsolete, *value);
428 char *upd = define_directive (c->updated, *value);
429 deprecated_directive (&variable_loc, old, upd);
430 free (old);
431 free (upd);
432 char *res = xstrdup (c->updated);
433 {
434 char *eq2 = strchr (res, '=');
435 if (eq2)
436 {
437 *eq2 = '\0';
438 *value = eq2 + 1;
439 }
440 }
441 return res;
442 }
443 }
444 return xstrdup (variable);
445}
446
447void
448muscle_percent_define_insert (char const *var, location variable_loc,
449 char const *value,
450 muscle_percent_define_how how)
451{
452 /* Backward compatibility. */
453 char *variable = muscle_percent_variable_update (var, variable_loc, &value);
454 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
455 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
456 char const *syncline_name =
457 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
458 char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
459
460 /* Command-line options are processed before the grammar file. */
461 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
462 && muscle_find_const (name))
463 {
464 muscle_percent_define_how how_old = atoi (muscle_find_const (how_name));
465 unsigned i = 0;
466 if (how_old == MUSCLE_PERCENT_DEFINE_F)
467 goto end;
468 complain_indent (&variable_loc, complaint, &i,
469 _("%%define variable %s redefined"),
470 quote (variable));
471 i += SUB_INDENT;
472 location loc = muscle_percent_define_get_loc (variable);
473 complain_indent (&loc, complaint, &i, _("previous definition"));
474 }
475
476 MUSCLE_INSERT_STRING (name, value);
477 muscle_insert (loc_name, "");
478 muscle_location_grow (loc_name, variable_loc);
479 muscle_insert (syncline_name, "");
480 muscle_syncline_grow (syncline_name, variable_loc);
481 muscle_user_name_list_grow ("percent_define_user_variables", variable,
482 variable_loc);
483 MUSCLE_INSERT_INT (how_name, how);
484 end:
485 free (variable);
486}
487
488/* This is used for backward compatibility, e.g., "%define api.pure"
489 supersedes "%pure-parser". */
490void
491muscle_percent_define_ensure (char const *variable, location loc,
492 bool value)
493{
494 char const *val = value ? "" : "false";
495 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
496
497 /* %pure-parser is deprecated in favor of '%define api.pure', so use
498 '%define api.pure' in a backward-compatible manner here. First,
499 don't complain if %pure-parser is specified multiple times. */
500 if (!muscle_find_const (name))
501 muscle_percent_define_insert (variable, loc, val,
502 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
503 /* In all cases, use api.pure now so that the backend doesn't complain if
504 the skeleton ignores api.pure, but do warn now if there's a previous
505 conflicting definition from an actual %define. */
506 if (muscle_percent_define_flag_if (variable) != value)
507 muscle_percent_define_insert (variable, loc, val,
508 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
509}
510
511char *
512muscle_percent_define_get (char const *variable)
513{
514 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
515 char const *usage_name =
516 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
517 char *value = string_decode (name);
518 if (!value)
519 value = xstrdup ("");
520
521 muscle_insert (usage_name, "");
522 return value;
523}
524
525location
526muscle_percent_define_get_loc (char const *variable)
527{
528 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
529 if (!muscle_find_const (loc_name))
530 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
531 "muscle_percent_define_get_loc", quote (variable));
532 return location_decode (loc_name);
533}
534
535char const *
536muscle_percent_define_get_syncline (char const *variable)
537{
538 char const *syncline_name =
539 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
540 char const *syncline = muscle_find_const (syncline_name);
541 if (!syncline)
542 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
543 "muscle_percent_define_get_syncline", quote (variable));
544 return syncline;
545}
546
547bool
548muscle_percent_define_ifdef (char const *variable)
549{
550 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
551 char const *usage_name =
552 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
553 char const *value = muscle_find_const (name);
554 if (value)
555 {
556 muscle_insert (usage_name, "");
557 return true;
558 }
559
560 return false;
561}
562
563bool
564muscle_percent_define_flag_if (char const *variable)
565{
566 char const *invalid_boolean_name =
567 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
568 bool result = false;
569
570 if (muscle_percent_define_ifdef (variable))
571 {
572 char *value = muscle_percent_define_get (variable);
573 if (value[0] == '\0' || STREQ (value, "true"))
574 result = true;
575 else if (STREQ (value, "false"))
576 result = false;
577 else if (!muscle_find_const (invalid_boolean_name))
578 {
579 muscle_insert (invalid_boolean_name, "");
580 location loc = muscle_percent_define_get_loc (variable);
581 complain (&loc, complaint,
582 _("invalid value for %%define Boolean variable %s"),
583 quote (variable));
584 }
585 free (value);
586 }
587 else
588 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
589 "muscle_percent_define_flag", quote (variable));
590
591 return result;
592}
593
594void
595muscle_percent_define_default (char const *variable, char const *value)
596{
597 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
598 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
599 char const *syncline_name =
600 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
601 if (!muscle_find_const (name))
602 {
603 location loc;
604 MUSCLE_INSERT_STRING (name, value);
605 loc.start.file = loc.end.file = "<default value>";
606 loc.start.line = loc.end.line = -1;
607 loc.start.column = loc.end.column = -1;
608 muscle_insert (loc_name, "");
609 muscle_location_grow (loc_name, loc);
610 muscle_insert (syncline_name, "");
611 }
612}
613
614void
615muscle_percent_define_check_values (char const * const *values)
616{
617 for (; *values; ++values)
618 {
619 char const * const *variablep = values;
620 char const *name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
621 char *value = string_decode (name);
622 if (value)
623 {
624 for (++values; *values; ++values)
625 {
626 if (STREQ (value, *values))
627 break;
628 }
629 if (!*values)
630 {
631 unsigned i = 0;
632 location loc = muscle_percent_define_get_loc (*variablep);
633 complain_indent (&loc, complaint, &i,
634 _("invalid value for %%define variable %s: %s"),
635 quote (*variablep), quote_n (1, value));
636 i += SUB_INDENT;
637 for (values = variablep + 1; *values; ++values)
638 complain_indent (&loc, complaint | no_caret | silent, &i,
639 _("accepted value: %s"), quote (*values));
640 }
641 else
642 {
643 while (*values)
644 ++values;
645 }
646 free (value);
647 }
648 else
649 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
650 "muscle_percent_define_check_values", quote (*variablep));
651 }
652}
653
654void
655muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
656 char const *code, location code_loc)
657{
658 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
659 muscle_code_grow (name, code, code_loc);
660 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
661 qualifier_loc);
662}
663
664
665/*------------------------------------------------.
666| Output the definition of ENTRY as a m4_define. |
667`------------------------------------------------*/
668
669static inline bool
670muscle_m4_output (muscle_entry *entry, FILE *out)
671{
672 fprintf (out,
673 "m4_define([b4_%s],\n"
674 "[[%s]])\n\n\n", entry->key, entry->value);
675 return true;
676}
677
678static bool
679muscle_m4_output_processor (void *entry, void *out)
680{
681 return muscle_m4_output (entry, out);
682}
683
684
685void
686muscles_m4_output (FILE *out)
687{
688 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
689}