1 /* Muscle table manager for Bison. 2 3 Copyright (C) 2001-2012 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. */ 33 typedef 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. */ 41 struct obstack muscle_obstack; 42 43 /* Initial capacity of muscles hash table. */ 44 #define HT_INITIAL_CAPACITY 257 45 46 static struct hash_table *muscle_table = NULL; 47 48 static bool 49 hash_compare_muscles (void const *x, void const *y) 50 { 51 muscle_entry const *m1 = x; 52 muscle_entry const *m2 = y; 53 return strcmp (m1->key, m2->key) == 0; 54 } 55 56 static size_t 57 hash_muscle (const void *x, size_t tablesize) 58 { 59 muscle_entry const *m = x; 60 return hash_string (m->key, tablesize); 61 } 62 63 /*-----------------------------------------------------------------. 64 | Create the MUSCLE_TABLE, and initialize it with default values. | 65 | Also set up the MUSCLE_OBSTACK. | 66 `-----------------------------------------------------------------*/ 67 68 static void 69 muscle_entry_free (void *entry) 70 { 71 muscle_entry *mentry = entry; 72 free (mentry->storage); 73 free (mentry); 74 } 75 76 void 77 muscle_init (void) 78 { 79 /* Initialize the muscle obstack. */ 80 obstack_init (&muscle_obstack); 81 82 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle, 83 hash_compare_muscles, muscle_entry_free); 84 85 /* Version and input file. */ 86 MUSCLE_INSERT_STRING ("version", VERSION); 87 } 88 89 90 /*------------------------------------------------------------. 91 | Free all the memory consumed by the muscle machinery only. | 92 `------------------------------------------------------------*/ 93 94 void 95 muscle_free (void) 96 { 97 hash_free (muscle_table); 98 obstack_free (&muscle_obstack, NULL); 99 } 100 101 102 103 /*------------------------------------------------------------. 104 | Insert (KEY, VALUE). If KEY already existed, overwrite the | 105 | previous value. | 106 `------------------------------------------------------------*/ 107 108 void 109 muscle_insert (char const *key, char const *value) 110 { 111 muscle_entry probe; 112 muscle_entry *entry; 113 114 probe.key = key; 115 entry = hash_lookup (muscle_table, &probe); 116 117 if (!entry) 118 { 119 /* First insertion in the hash. */ 120 entry = xmalloc (sizeof *entry); 121 entry->key = key; 122 if (!hash_insert (muscle_table, entry)) 123 xalloc_die (); 124 } 125 else 126 free (entry->storage); 127 entry->value = value; 128 entry->storage = NULL; 129 } 130 131 132 /*-------------------------------------------------------------------. 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. | 136 `-------------------------------------------------------------------*/ 137 138 void 139 muscle_grow (const char *key, const char *val, const char *separator) 140 { 141 muscle_entry probe; 142 muscle_entry *entry = NULL; 143 144 probe.key = key; 145 entry = hash_lookup (muscle_table, &probe); 146 147 if (!entry) 148 { 149 /* First insertion in the hash. */ 150 entry = xmalloc (sizeof *entry); 151 entry->key = key; 152 if (!hash_insert (muscle_table, entry)) 153 xalloc_die (); 154 entry->value = entry->storage = xstrdup (val); 155 } 156 else 157 { 158 /* Grow the current value. */ 159 char *new_val; 160 obstack_sgrow (&muscle_obstack, entry->value); 161 free (entry->storage); 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); 166 entry->value = entry->storage = xstrdup (new_val); 167 obstack_free (&muscle_obstack, new_val); 168 } 169 } 170 171 /*------------------------------------------------------------------. 172 | Using muscle_grow, append a synchronization line for the location | 173 | LOC to the current value of KEY. | 174 `------------------------------------------------------------------*/ 175 176 static void 177 muscle_syncline_grow (char const *key, location loc) 178 { 179 char *extension = NULL; 180 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line); 181 obstack_quote (&muscle_obstack, 182 quotearg_style (c_quoting_style, loc.start.file)); 183 obstack_sgrow (&muscle_obstack, ")["); 184 obstack_1grow (&muscle_obstack, 0); 185 extension = obstack_finish (&muscle_obstack); 186 muscle_grow (key, extension, ""); 187 obstack_free (&muscle_obstack, extension); 188 } 189 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 196 void 197 muscle_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 203 204 void muscle_pair_list_grow (const char *muscle, 205 const char *a1, const char *a2) 206 { 207 char *pair; 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, "]"); 213 obstack_1grow (&muscle_obstack, 0); 214 pair = obstack_finish (&muscle_obstack); 215 muscle_grow (muscle, pair, ",\n"); 216 obstack_free (&muscle_obstack, pair); 217 } 218 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 225 char const * 226 muscle_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 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 `----------------------------------------------------------------------------*/ 244 245 char * 246 muscle_find (char const *key) 247 { 248 muscle_entry probe; 249 muscle_entry *result = NULL; 250 251 probe.key = key; 252 result = hash_lookup (muscle_table, &probe); 253 if (result) 254 { 255 aver (result->value == result->storage); 256 return result->storage; 257 } 258 return NULL; 259 } 260 261 262 /* In the format `file_name:line.column', append BOUND to MUSCLE. Use 263 digraphs for special characters in the file name. */ 264 265 static void 266 muscle_boundary_grow (char const *key, boundary bound) 267 { 268 char *extension; 269 obstack_sgrow (&muscle_obstack, "[["); 270 obstack_escape (&muscle_obstack, bound.file); 271 obstack_1grow (&muscle_obstack, ':'); 272 obstack_printf (&muscle_obstack, "%d", bound.line); 273 obstack_1grow (&muscle_obstack, '.'); 274 obstack_printf (&muscle_obstack, "%d", bound.column); 275 obstack_sgrow (&muscle_obstack, "]]"); 276 obstack_1grow (&muscle_obstack, '\0'); 277 extension = obstack_finish (&muscle_obstack); 278 muscle_grow (key, extension, ""); 279 obstack_free (&muscle_obstack, extension); 280 } 281 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 287 static void 288 muscle_location_grow (char const *key, location loc) 289 { 290 muscle_boundary_grow (key, loc.start); 291 muscle_grow (key, "", ", "); 292 muscle_boundary_grow (key, loc.end); 293 } 294 295 #define COMMON_DECODE(Value) \ 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)); \ 312 break; 313 314 /* Reverse of obstack_escape. */ 315 static char * 316 string_decode (char const *key) 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 { 328 COMMON_DECODE (value) 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 341 /* Reverse of muscle_location_grow. */ 342 static location 343 location_decode (char const *key) 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 { 353 COMMON_DECODE (value) 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; 383 } 384 aver (false); 385 return loc; 386 } 387 388 void 389 muscle_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 399 /** If the \a variable name is obsolete, return the name to use, 400 * otherwise \a variable. */ 401 static 402 char const * 403 muscle_percent_variable_update (char const *variable) 404 { 405 typedef struct 406 { 407 const char *obsolete; 408 const char *updated; 409 } conversion_type; 410 const conversion_type conversion[] = 411 { 412 { "api.push_pull", "api.push-pull", }, 413 { "location_type", "api.location.type", }, 414 { "lr.keep_unreachable_states", "lr.keep-unreachable-states", }, 415 }; 416 char const *res = variable; 417 int i; 418 for (i = 0; i < ARRAY_CARDINALITY (conversion); ++i) 419 if (STREQ (conversion[i].obsolete, variable)) 420 { 421 res = conversion[i].updated; 422 break; 423 } 424 return res; 425 } 426 427 void 428 muscle_percent_define_insert (char const *var, location variable_loc, 429 char const *value, 430 muscle_percent_define_how how) 431 { 432 /* Backward compatibility. */ 433 char const *variable = muscle_percent_variable_update (var); 434 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")"); 435 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")"); 436 char const *syncline_name = 437 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")"); 438 char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")"); 439 440 /* Command-line options are processed before the grammar file. */ 441 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE 442 && muscle_find_const (name)) 443 { 444 unsigned i = 0; 445 muscle_percent_define_how how_old = 446 atoi (muscle_find_const (how_name)); 447 if (how_old == MUSCLE_PERCENT_DEFINE_F) 448 return; 449 complain_at_indent (variable_loc, &i, 450 _("%%define variable %s redefined"), quote (variable)); 451 i += SUB_INDENT; 452 complain_at_indent (muscle_percent_define_get_loc (variable), &i, 453 _("previous definition")); 454 } 455 456 MUSCLE_INSERT_STRING (name, value); 457 muscle_insert (loc_name, ""); 458 muscle_location_grow (loc_name, variable_loc); 459 muscle_insert (syncline_name, ""); 460 muscle_syncline_grow (syncline_name, variable_loc); 461 muscle_user_name_list_grow ("percent_define_user_variables", variable, 462 variable_loc); 463 MUSCLE_INSERT_INT (how_name, how); 464 } 465 466 char * 467 muscle_percent_define_get (char const *variable) 468 { 469 char const *name; 470 char const *usage_name; 471 char *value; 472 473 name = UNIQSTR_CONCAT ("percent_define(", variable, ")"); 474 usage_name = UNIQSTR_CONCAT ("percent_define_bison_variables(", 475 variable, ")"); 476 477 muscle_insert (usage_name, ""); 478 value = string_decode (name); 479 if (!value) 480 value = xstrdup (""); 481 return value; 482 } 483 484 location 485 muscle_percent_define_get_loc (char const *variable) 486 { 487 char const *loc_name; 488 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")"); 489 if (!muscle_find_const (loc_name)) 490 fatal(_("%s: undefined %%define variable %s"), 491 "muscle_percent_define_get_loc", quote (variable)); 492 return location_decode (loc_name); 493 } 494 495 char const * 496 muscle_percent_define_get_syncline (char const *variable) 497 { 498 char const *syncline_name; 499 char const *syncline; 500 syncline_name = 501 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")"); 502 syncline = muscle_find_const (syncline_name); 503 if (!syncline) 504 fatal(_("%s: undefined %%define variable %s"), 505 "muscle_percent_define_get_syncline", quote (variable)); 506 return syncline; 507 } 508 509 bool 510 muscle_percent_define_ifdef (char const *variable) 511 { 512 char const *name; 513 char const *usage_name; 514 char const *value; 515 516 name = UNIQSTR_CONCAT ("percent_define(", variable, ")"); 517 usage_name = 518 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")"); 519 520 value = muscle_find_const (name); 521 if (value) 522 { 523 muscle_insert (usage_name, ""); 524 return true; 525 } 526 527 return false; 528 } 529 530 bool 531 muscle_percent_define_flag_if (char const *variable) 532 { 533 char const *invalid_boolean_name; 534 bool result = false; 535 536 invalid_boolean_name = 537 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")"); 538 539 if (muscle_percent_define_ifdef (variable)) 540 { 541 char *value = muscle_percent_define_get (variable); 542 if (value[0] == '\0' || 0 == strcmp (value, "true")) 543 result = true; 544 else if (0 == strcmp (value, "false")) 545 result = false; 546 else if (!muscle_find_const (invalid_boolean_name)) 547 { 548 muscle_insert (invalid_boolean_name, ""); 549 complain_at(muscle_percent_define_get_loc (variable), 550 _("invalid value for %%define Boolean variable %s"), 551 quote (variable)); 552 } 553 free (value); 554 } 555 else 556 fatal(_("%s: undefined %%define variable %s"), 557 "muscle_percent_define_flag", quote (variable)); 558 559 return result; 560 } 561 562 void 563 muscle_percent_define_default (char const *variable, char const *value) 564 { 565 char const *name; 566 char const *loc_name; 567 char const *syncline_name; 568 name = UNIQSTR_CONCAT ("percent_define(", variable, ")"); 569 loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")"); 570 syncline_name = 571 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")"); 572 if (!muscle_find_const (name)) 573 { 574 location loc; 575 MUSCLE_INSERT_STRING (name, value); 576 loc.start.file = loc.end.file = "<default value>"; 577 loc.start.line = loc.end.line = -1; 578 loc.start.column = loc.end.column = -1; 579 muscle_insert (loc_name, ""); 580 muscle_location_grow (loc_name, loc); 581 muscle_insert (syncline_name, ""); 582 } 583 } 584 585 void 586 muscle_percent_define_check_values (char const * const *values) 587 { 588 for (; *values; ++values) 589 { 590 char const * const *variablep = values; 591 char const *name; 592 char *value; 593 594 name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")"); 595 596 value = string_decode (name); 597 if (value) 598 { 599 for (++values; *values; ++values) 600 { 601 if (0 == strcmp (value, *values)) 602 break; 603 } 604 if (!*values) 605 { 606 unsigned i = 0; 607 location loc = muscle_percent_define_get_loc (*variablep); 608 complain_at_indent (loc, &i, 609 _("invalid value for %%define variable %s: %s"), 610 quote (*variablep), quote_n (1, value)); 611 i += SUB_INDENT; 612 for (values = variablep + 1; *values; ++values) 613 complain_at_indent (loc, &i, _("accepted value: %s"), 614 quote (*values)); 615 } 616 else 617 { 618 while (*values) 619 ++values; 620 } 621 free (value); 622 } 623 else 624 fatal (_("%s: undefined %%define variable %s"), 625 "muscle_percent_define_check_values", quote (*variablep)); 626 } 627 } 628 629 void 630 muscle_percent_code_grow (char const *qualifier, location qualifier_loc, 631 char const *code, location code_loc) 632 { 633 char const *name; 634 name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")"); 635 muscle_code_grow (name, code, code_loc); 636 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier, 637 qualifier_loc); 638 } 639 640 641 /*------------------------------------------------. 642 | Output the definition of ENTRY as a m4_define. | 643 `------------------------------------------------*/ 644 645 static inline bool 646 muscle_m4_output (muscle_entry *entry, FILE *out) 647 { 648 fprintf (out, "m4_define([b4_%s],\n", entry->key); 649 fprintf (out, "[[%s]])\n\n\n", entry->value); 650 return true; 651 } 652 653 static bool 654 muscle_m4_output_processor (void *entry, void *out) 655 { 656 return muscle_m4_output (entry, out); 657 } 658 659 660 /*----------------------------------------------------------------. 661 | Output the definition of all the current muscles into a list of | 662 | m4_defines. | 663 `----------------------------------------------------------------*/ 664 665 void 666 muscles_m4_output (FILE *out) 667 { 668 hash_do_for_each (muscle_table, muscle_m4_output_processor, out); 669 } 670