]> git.saurik.com Git - bison.git/blame - src/muscle_tab.c
Fix some error-reporting macro bugs.
[bison.git] / src / muscle_tab.c
CommitLineData
e00b6826
PE
1/* Muscle table manager for Bison.
2
279cabb6 3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
05ac60f3 4 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);
48b16bbc 88 MUSCLE_INSERT_C_STRING ("file_name", grammar_file);
f753cd62
MA
89}
90
592e8d4d
AD
91
92/*------------------------------------------------------------.
93| Free all the memory consumed by the muscle machinery only. |
94`------------------------------------------------------------*/
95
96void
97muscle_free (void)
98{
99 hash_free (muscle_table);
100 obstack_free (&muscle_obstack, NULL);
101}
102
103
104
ae7453f2
AD
105/*------------------------------------------------------------.
106| Insert (KEY, VALUE). If KEY already existed, overwrite the |
107| previous value. |
108`------------------------------------------------------------*/
109
a870c567 110void
eb095650 111muscle_insert (char const *key, char const *value)
f753cd62 112{
8322e8f5 113 muscle_entry probe;
da2a7671 114 muscle_entry *entry;
e9bca3ad 115
ae7453f2
AD
116 probe.key = key;
117 entry = hash_lookup (muscle_table, &probe);
beda758b
AD
118
119 if (!entry)
120 {
121 /* First insertion in the hash. */
da2a7671 122 entry = xmalloc (sizeof *entry);
beda758b
AD
123 entry->key = key;
124 hash_insert (muscle_table, entry);
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
AD
152 entry->key = key;
153 hash_insert (muscle_table, entry);
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
171
cd3684cf
AD
172/*------------------------------------------------------------------.
173| Append VALUE to the current value of KEY, using muscle_grow. But |
174| in addition, issue a synchronization line for the location LOC. |
175`------------------------------------------------------------------*/
176
177void
178muscle_code_grow (const char *key, const char *val, location loc)
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));
184 obstack_sgrow (&muscle_obstack, "]])[\n");
185 obstack_sgrow (&muscle_obstack, val);
186 obstack_1grow (&muscle_obstack, 0);
187 extension = obstack_finish (&muscle_obstack);
188 muscle_grow (key, extension, "");
eb095650 189 obstack_free (&muscle_obstack, extension);
cd3684cf
AD
190}
191
192
ae7453f2
AD
193void muscle_pair_list_grow (const char *muscle,
194 const char *a1, const char *a2)
195{
66d30cd4 196 char *pair;
7ecec4dd
JD
197 obstack_sgrow (&muscle_obstack, "[[[");
198 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a1);
199 obstack_sgrow (&muscle_obstack, "]], [[");
200 MUSCLE_OBSTACK_SGROW (&muscle_obstack, a2);
201 obstack_sgrow (&muscle_obstack, "]]]");
ae7453f2 202 obstack_1grow (&muscle_obstack, 0);
66d30cd4
AD
203 pair = obstack_finish (&muscle_obstack);
204 muscle_grow (muscle, pair, ",\n");
205 obstack_free (&muscle_obstack, pair);
ae7453f2
AD
206}
207
7eb8a0bc
JD
208
209/*----------------------------------------------------------------------------.
210| Find the value of muscle KEY. Unlike MUSCLE_FIND, this is always reliable |
211| to determine whether KEY has a value. |
212`----------------------------------------------------------------------------*/
213
214char const *
215muscle_find_const (char const *key)
216{
217 muscle_entry probe;
218 muscle_entry *result = NULL;
219
220 probe.key = key;
221 result = hash_lookup (muscle_table, &probe);
222 if (result)
223 return result->value;
224 return NULL;
225}
226
227
4502eadc
JD
228/*----------------------------------------------------------------------------.
229| Find the value of muscle KEY. Abort if muscle_insert was invoked more |
230| recently than muscle_grow for KEY since muscle_find can't return a |
231| char const *. |
232`----------------------------------------------------------------------------*/
ae7453f2 233
ff5150d9 234char *
7eb8a0bc 235muscle_find (char const *key)
f753cd62 236{
8322e8f5
PE
237 muscle_entry probe;
238 muscle_entry *result = NULL;
e9bca3ad 239
ae7453f2
AD
240 probe.key = key;
241 result = hash_lookup (muscle_table, &probe);
4502eadc
JD
242 if (result)
243 {
244 aver (result->value == result->storage);
245 return result->storage;
246 }
247 return NULL;
f753cd62 248}
be2a1a68
AD
249
250
9611cfa2
JD
251void
252muscle_boundary_grow (char const *key, boundary bound)
253{
254 char *extension;
255 MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file);
256 obstack_1grow (&muscle_obstack, ':');
257 obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
258 obstack_1grow (&muscle_obstack, '.');
259 obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
260 obstack_1grow (&muscle_obstack, '\0');
261 extension = obstack_finish (&muscle_obstack);
262 muscle_grow (key, extension, "");
263 obstack_free (&muscle_obstack, extension);
264}
265
266void
267muscle_location_grow (char const *key, location loc)
268{
269 muscle_grow (key, "[[", "");
270 muscle_boundary_grow (key, loc.start);
271 muscle_grow (key, "]], [[", "");
272 muscle_boundary_grow (key, loc.end);
273 muscle_grow (key, "]]", "");
274}
275
f124d423
JD
276#define MUSCLE_COMMON_DECODE(Value) \
277 case '$': \
278 aver (*++(Value) == ']'); \
279 aver (*++(Value) == '['); \
280 obstack_sgrow (&muscle_obstack, "$"); \
281 break; \
282 case '@': \
283 switch (*++(Value)) \
284 { \
285 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
286 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
287 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
288 default: aver (false); break; \
289 } \
290 break; \
291 default: \
292 obstack_1grow (&muscle_obstack, *(Value)); \
293 break;
294
295/* Reverse of MUSCLE_OBSTACK_SGROW. */
296static char *
297muscle_string_decode (char const *key)
298{
299 char const *value;
300 char *value_decoded;
301 char *result;
302
303 value = muscle_find_const (key);
304 if (!value)
305 return NULL;
306 do {
307 switch (*value)
308 {
309 MUSCLE_COMMON_DECODE (value)
310 case '[':
311 case ']':
312 aver (false);
313 break;
314 }
315 } while (*value++);
316 value_decoded = obstack_finish (&muscle_obstack);
317 result = xstrdup (value_decoded);
318 obstack_free (&muscle_obstack, value_decoded);
319 return result;
320}
321
9611cfa2
JD
322/* Reverse of muscle_location_grow. */
323static location
324muscle_location_decode (char const *key)
325{
326 location loc;
327 char const *value = muscle_find_const (key);
328 aver (value);
329 aver (*value == '[');
330 aver (*++value == '[');
331 while (*++value)
332 switch (*value)
333 {
f124d423 334 MUSCLE_COMMON_DECODE (value)
9611cfa2
JD
335 case '[':
336 aver (false);
337 break;
338 case ']':
339 {
340 char *boundary_str;
341 aver (*++value == ']');
342 obstack_1grow (&muscle_obstack, '\0');
343 boundary_str = obstack_finish (&muscle_obstack);
344 switch (*++value)
345 {
346 case ',':
347 boundary_set_from_string (&loc.start, boundary_str);
348 obstack_free (&muscle_obstack, boundary_str);
349 aver (*++value == ' ');
350 aver (*++value == '[');
351 aver (*++value == '[');
352 break;
353 case '\0':
354 boundary_set_from_string (&loc.end, boundary_str);
355 obstack_free (&muscle_obstack, boundary_str);
356 return loc;
357 break;
358 default:
359 aver (false);
360 break;
361 }
362 }
363 break;
9611cfa2
JD
364 }
365 aver (false);
366 return loc;
367}
368
369void
370muscle_user_name_list_grow (char const *key, char const *user_name,
371 location loc)
372{
373 muscle_grow (key, "[[[[", ",");
374 muscle_grow (key, user_name, "");
375 muscle_grow (key, "]], ", "");
376 muscle_location_grow (key, loc);
377 muscle_grow (key, "]]", "");
378}
379
380#define MUSCLE_USER_NAME_CONVERT(NAME, PREFIX, USER_NAME, SUFFIX) \
381do { \
382 char *tmp; \
383 size_t length = strlen ((USER_NAME)); \
384 tmp = xmalloc (sizeof (PREFIX) - 1 + length + sizeof (SUFFIX)); \
385 strcpy (tmp, (PREFIX)); \
386 strcpy (tmp + sizeof (PREFIX) - 1, (USER_NAME)); \
387 strcpy (tmp + sizeof (PREFIX) - 1 + length, (SUFFIX)); \
388 (NAME) = uniqstr_new (tmp); \
389 free (tmp); \
390} while (0)
391
392void
393muscle_percent_define_insert (char const *variable, location variable_loc,
394 char const *value)
395{
396 char const *name;
397 char const *loc_name;
398
399 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
400 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
401
402 if (muscle_find_const (name))
403 {
404 warn_at (variable_loc, _("%s `%s' redefined"),
405 "%define variable", variable);
406 warn_at (muscle_location_decode (loc_name), _("previous definition"));
407 }
408 MUSCLE_INSERT_STRING (name, value);
409
410 muscle_insert (loc_name, "");
411 muscle_location_grow (loc_name, variable_loc);
412 muscle_user_name_list_grow ("percent_define_user_variables", variable,
413 variable_loc);
414}
415
f124d423
JD
416char *
417muscle_percent_define_get (char const *variable)
418{
419 char const *name;
420 char const *usage_name;
421 char *value;
422
423 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
424 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
425 variable, ")");
426
427 muscle_insert (usage_name, "");
428 value = muscle_string_decode (name);
429 if (!value)
430 value = xstrdup ("");
431 return value;
432}
433
434bool
435muscle_percent_define_ifdef (char const *variable)
436{
437 char const *name;
438 char const *usage_name;
439 char const *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 value = muscle_find_const (name);
446 if (value)
447 {
448 muscle_insert (usage_name, "");
449 return true;
450 }
451
452 return false;
453}
454
9611cfa2
JD
455bool
456muscle_percent_define_flag_if (char const *variable)
457{
458 char const *name;
459 char const *loc_name;
460 char const *usage_name;
cbd50549 461 char const *invalid_boolean_name;
9611cfa2
JD
462 bool result = false;
463
464 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
465 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
466 MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
467 variable, ")");
cbd50549
JD
468 MUSCLE_USER_NAME_CONVERT (invalid_boolean_name,
469 "percent_define_invalid_boolean(", variable, ")");
9611cfa2 470
f124d423 471 if (muscle_percent_define_ifdef (variable))
9611cfa2 472 {
f124d423 473 char *value = muscle_percent_define_get (variable);
9611cfa2
JD
474 if (value[0] == '\0' || 0 == strcmp (value, "true"))
475 result = true;
476 else if (0 == strcmp (value, "false"))
477 result = false;
cbd50549
JD
478 else if (!muscle_find_const (invalid_boolean_name))
479 {
480 muscle_insert (invalid_boolean_name, "");
481 complain_at(muscle_location_decode (loc_name),
922bdd7f 482 _("invalid value for %%define Boolean variable `%s'"),
cbd50549
JD
483 variable);
484 }
f124d423 485 free (value);
9611cfa2
JD
486 }
487 else
488 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
489 variable);
490
9611cfa2
JD
491 return result;
492}
493
494void
495muscle_percent_define_default (char const *variable, char const *value)
496{
497 char const *name;
498 char const *loc_name;
499 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
500 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
501 if (!muscle_find_const (name))
502 {
503 location loc;
504 MUSCLE_INSERT_STRING (name, value);
505 loc.start.file = loc.end.file = "[Bison:muscle_percent_define_default]";
506 loc.start.line = loc.start.column = 0;
507 loc.end.line = loc.end.column = 0;
508 muscle_insert (loc_name, "");
509 muscle_location_grow (loc_name, loc);
510 }
511}
512
f124d423 513void
b1a81613 514muscle_percent_define_check_values (char const * const *values)
f124d423 515{
b1a81613
JD
516 for (; *values; ++values)
517 {
518 char const *variable = *values;
519 char const *name;
520 char const *loc_name;
521 char *value;
522
523 MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
524 MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
525
526 value = muscle_string_decode (name);
527 if (value)
528 {
529 bool valid = false;
530 for (++values; *values; ++values)
531 {
532 if (0 == strcmp (value, *values))
533 {
534 valid = true;
535 while (*values)
536 ++values;
537 break;
538 }
539 }
540 if (!valid)
541 complain_at(muscle_location_decode (loc_name),
542 _("invalid value for %%define variable `%s': `%s'"),
543 variable, value);
544 free (value);
545 }
546 else
547 fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_check_values"),
548 variable);
549 }
f124d423
JD
550}
551
9611cfa2
JD
552void
553muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
554 char const *code, location code_loc)
555{
556 char const *name;
557 MUSCLE_USER_NAME_CONVERT (name, "percent_code(", qualifier, ")");
558 muscle_code_grow (name, code, code_loc);
559 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
560 qualifier_loc);
561}
562
563
ae7453f2
AD
564/*------------------------------------------------.
565| Output the definition of ENTRY as a m4_define. |
566`------------------------------------------------*/
be2a1a68 567
e00b6826 568static inline bool
8322e8f5 569muscle_m4_output (muscle_entry *entry, FILE *out)
be2a1a68
AD
570{
571 fprintf (out, "m4_define([b4_%s],\n", entry->key);
ae7453f2 572 fprintf (out, "[[%s]])\n\n\n", entry->value);
e00b6826
PE
573 return true;
574}
575
576static bool
577muscle_m4_output_processor (void *entry, void *out)
578{
579 return muscle_m4_output (entry, out);
be2a1a68
AD
580}
581
582
ae7453f2
AD
583/*----------------------------------------------------------------.
584| Output the definition of all the current muscles into a list of |
585| m4_defines. |
586`----------------------------------------------------------------*/
be2a1a68
AD
587
588void
589muscles_m4_output (FILE *out)
590{
e00b6826 591 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
be2a1a68 592}