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