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. */ 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 strcmp (m1->key, m2->key) == 0; 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/*-----------------------------------------------------------------. 64| Create the MUSCLE_TABLE, and initialize it with default values. | 65| Also set up the MUSCLE_OBSTACK. | 66`-----------------------------------------------------------------*/ 67 68static void 69muscle_entry_free (void *entry) 70{ 71 muscle_entry *mentry = entry; 72 free (mentry->storage); 73 free (mentry); 74} 75 76void 77muscle_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 94void 95muscle_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 108void 109muscle_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 138void 139muscle_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 176static void 177muscle_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 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 203 204void 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 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 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 245char * 246muscle_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 265static void 266muscle_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 287static void 288muscle_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. */ 315static char * 316string_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. */ 342static location 343location_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 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 399/** If the \a variable name is obsolete, return the name to use, 400 * otherwise \a variable. */ 401static 402char const * 403muscle_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 427void 428muscle_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 466char * 467muscle_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 484location 485muscle_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 495char const * 496muscle_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 509bool 510muscle_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 530bool 531muscle_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 562void 563muscle_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 585void 586muscle_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 629void 630muscle_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 645static inline bool 646muscle_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 653static bool 654muscle_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 665void 666muscles_m4_output (FILE *out) 667{ 668 hash_do_for_each (muscle_table, muscle_m4_output_processor, out); 669} 670