1/* Bison Action Scanner -*- C -*- 2 3 Copyright (C) 2006-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%option debug nodefault noinput nounput noyywrap never-interactive 21%option prefix="code_" outfile="lex.yy.c" 22 23%{ 24/* Work around a bug in flex 2.5.31. See Debian bug 333231 25 <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>. */ 26#undef code_wrap 27#define code_wrap() 1 28 29#define FLEX_PREFIX(Id) code_ ## Id 30#include "flex-scanner.h" 31 32#include "complain.h" 33#include "reader.h" 34#include "getargs.h" 35#include "scan-code.h" 36#include "symlist.h" 37 38#include <c-ctype.h> 39#include <get-errno.h> 40#include <quote.h> 41 42/* The current calling start condition: SC_RULE_ACTION or 43 SC_SYMBOL_ACTION. */ 44# define YY_DECL static char *code_lex (code_props *self, int sc_context) 45YY_DECL; 46 47#define YY_USER_ACTION location_compute (loc, &loc->end, yytext, yyleng); 48 49static char *fetch_type_name (char *cp, char const **type_name, 50 location dollar_loc); 51 52static void handle_action_dollar (symbol_list *rule, char *cp, 53 location dollar_loc); 54static void handle_action_at (symbol_list *rule, char *cp, location at_loc); 55 56/* A string to be pushed to obstack after dollar/at has been handled. */ 57static char *ref_tail_fields; 58 59static location the_location; 60static location *loc = &the_location; 61 62/* A string representing the most recent translation. */ 63static char *last_string; 64 65/* True if an untyped $$ or $n was seen. */ 66static bool untyped_var_seen; 67 68%} 69 /* C and C++ comments in code. */ 70%x SC_COMMENT SC_LINE_COMMENT 71 /* Strings and characters in code. */ 72%x SC_STRING SC_CHARACTER 73 /* Whether in a rule or symbol action. Specifies the translation 74 of $ and @. */ 75%x SC_RULE_ACTION SC_SYMBOL_ACTION 76 77 78/* POSIX says that a tag must be both an id and a C union member, but 79 historically almost any character is allowed in a tag. We disallow 80 NUL and newline, as this simplifies our implementation. */ 81tag [^\0\n>]+ 82 83/* Zero or more instances of backslash-newline. Following GCC, allow 84 white space between the backslash and the newline. */ 85splice (\\[ \f\t\v]*\n)* 86 87/* C style identifier. Must start with letter. Will be used for 88 named symbol references. Shall be kept synchronized with 89 scan-gram.l "letter" and "id". */ 90letter [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_] 91id {letter}({letter}|[-0-9])* 92ref -?[0-9]+|{id}|"["{id}"]"|"$" 93 94%% 95 96%{ 97 /* Nesting level of the current code in braces. */ 98 int braces_level = 0; 99 100 /* Whether a semicolon is probably needed. 101 102 The heuristic is that a semicolon is not needed after '{', '}', 103 ';', or a C preprocessor directive, and that whitespaces and 104 comments do not affect this flag. Note that '{' does not need a 105 semicolon because of '{}'. A semicolon may be needed before a 106 cpp directive, but don't bother. 107 108 While it is maintained in several start-conditions (factoring 109 opportunities), it is meaningful only for SC_RULE_ACTION. */ 110 bool need_semicolon = false; 111 112 /* Whether in a C preprocessor directive. Don't use a start condition 113 for this because, at the end of strings and comments, we still need 114 to know whether we're in a directive. */ 115 bool in_cpp = false; 116 117 /* This scanner is special: it is invoked only once, henceforth 118 is expected to return only once. This initialization is 119 therefore done once per action to translate. */ 120 aver (sc_context == SC_SYMBOL_ACTION 121 || sc_context == SC_RULE_ACTION 122 || sc_context == INITIAL); 123 BEGIN sc_context; 124%} 125 126 /*------------------------------------------------------------. 127 | Scanning a C comment. The initial '/ *' is already eaten. | 128 `------------------------------------------------------------*/ 129 130<SC_COMMENT> 131{ 132 "*"{splice}"/" STRING_GROW; BEGIN sc_context; 133} 134 135 136 /*--------------------------------------------------------------. 137 | Scanning a line comment. The initial '//' is already eaten. | 138 `--------------------------------------------------------------*/ 139 140<SC_LINE_COMMENT> 141{ 142 "\n" STRING_GROW; BEGIN sc_context; 143 {splice} STRING_GROW; 144} 145 146 147 /*--------------------------------------------. 148 | Scanning user-code characters and strings. | 149 `--------------------------------------------*/ 150 151<SC_CHARACTER,SC_STRING> 152{ 153 {splice}|\\{splice}. STRING_GROW; 154} 155 156<SC_CHARACTER> 157{ 158 "'" STRING_GROW; BEGIN sc_context; 159} 160 161<SC_STRING> 162{ 163 "\"" STRING_GROW; BEGIN sc_context; 164} 165 166 167<SC_RULE_ACTION,SC_SYMBOL_ACTION> 168{ 169 "'" { 170 STRING_GROW; 171 BEGIN SC_CHARACTER; 172 need_semicolon = true; 173 } 174 "\"" { 175 STRING_GROW; 176 BEGIN SC_STRING; 177 need_semicolon = true; 178 } 179 "/"{splice}"*" { 180 STRING_GROW; 181 BEGIN SC_COMMENT; 182 } 183 "/"{splice}"/" { 184 STRING_GROW; 185 BEGIN SC_LINE_COMMENT; 186 } 187 [$@] { 188 warn_at (*loc, _("stray '%s'"), yytext); 189 obstack_escape (&obstack_for_string, yytext); 190 need_semicolon = true; 191 } 192 [\[\]] { 193 obstack_escape (&obstack_for_string, yytext); 194 need_semicolon = true; 195 } 196} 197 198<SC_RULE_ACTION> 199{ 200 "$"("<"{tag}">")?{ref} { 201 ref_tail_fields = NULL; 202 handle_action_dollar (self->rule, yytext, *loc); 203 if (ref_tail_fields) 204 obstack_sgrow (&obstack_for_string, ref_tail_fields); 205 need_semicolon = true; 206 } 207 "@"{ref} { 208 ref_tail_fields = NULL; 209 handle_action_at (self->rule, yytext, *loc); 210 if (ref_tail_fields) 211 obstack_sgrow (&obstack_for_string, ref_tail_fields); 212 need_semicolon = true; 213 } 214 215 ";" STRING_GROW; need_semicolon = false; 216 "{" STRING_GROW; ++braces_level; need_semicolon = false; 217 "}" { 218 bool outer_brace = --braces_level == 0; 219 220 /* As an undocumented Bison extension, append ';' before the last 221 brace in braced code, so that the user code can omit trailing 222 ';'. But do not append ';' if emulating Yacc, since Yacc does 223 not append one. This is deprecated since release 2.4.1. */ 224 if (outer_brace && !yacc_flag && language_prio == default_prio 225 && skeleton_prio == default_prio && need_semicolon && ! in_cpp) 226 { 227 unsigned int indent = 0; 228 warn_at_indent (*loc, &indent, 229 _("a ';' might be needed at the end of action code")); 230 indent += SUB_INDENT; 231 warn_at_indent (*loc, &indent, 232 _("future versions of Bison will not add the ';'")); 233 obstack_1grow (&obstack_for_string, ';'); 234 } 235 236 STRING_GROW; 237 need_semicolon = false; 238 } 239 240 /* Preprocessing directives should only be recognized at the beginning 241 of lines, allowing whitespace including comments, but in C/C++, 242 '#' can only be the start of preprocessor directives or within 243 '#define' directives anyway, so don't bother with begin of line. */ 244 "#" STRING_GROW; in_cpp = true; 245 246 {splice} STRING_GROW; 247 [\n\r] STRING_GROW; if (in_cpp) in_cpp = need_semicolon = false; 248 [ \t\f] STRING_GROW; 249 250 /* YYFAIL is undocumented and was formally deprecated in Bison 251 2.4.2. */ 252 YYFAIL { 253 STRING_GROW; need_semicolon = true; 254 warn_at (*loc, _("use of YYFAIL, which is deprecated and will be" 255 " removed")); 256 } 257 258 /* The sole purpose of this is to make sure identifiers that merely 259 contain YYFAIL don't produce the above warning. */ 260 [A-Za-z_][0-9A-Za-z_]* STRING_GROW; need_semicolon = true; 261 262 . STRING_GROW; need_semicolon = true; 263} 264 265<SC_SYMBOL_ACTION> 266{ 267 "$"("<"{tag}">")?"$" { 268 const char *type_name = NULL; 269 fetch_type_name (yytext + 1, &type_name, *loc)[-1] = 0; 270 obstack_sgrow (&obstack_for_string, "]b4_dollar_dollar("); 271 obstack_quote (&obstack_for_string, type_name); 272 obstack_sgrow (&obstack_for_string, ")["); 273 self->is_value_used = true; 274 } 275 "@$" { 276 obstack_sgrow (&obstack_for_string, "]b4_at_dollar["); 277 locations_flag = true; 278 } 279} 280 281 282<*> 283{ 284 /* Escape M4 quoting characters in C code. */ 285 [$@\[\]] obstack_escape (&obstack_for_string, yytext); 286 287 /* By default, grow the string obstack with the input. */ 288 .|\n STRING_GROW; 289 290 /* End of processing. */ 291 <<EOF>> STRING_FINISH; return last_string; 292} 293 294%% 295 296static inline bool 297is_dot_or_dash (char ch) 298{ 299 return ch == '.' || ch == '-'; 300} 301 302static inline bool 303contains_dot_or_dash (const char* p) 304{ 305 for (; *p; ++p) 306 if (is_dot_or_dash (*p)) 307 return true; 308 return false; 309} 310 311/* Defines a variant of a symbolic name resolution. */ 312typedef struct 313{ 314 /* Index in symbol list. */ 315 unsigned symbol_index; 316 317 /* Matched symbol id and loc. */ 318 uniqstr id; 319 location loc; 320 321 /* Hiding named reference. */ 322 named_ref* hidden_by; 323 324 /* Error flags. May contain zero (no errors) or 325 a combination of VARIANT_* values. */ 326 unsigned err; 327} variant; 328 329/* Set when the variant refers to a symbol hidden 330 by an explicit symbol reference. */ 331#define VARIANT_HIDDEN (1 << 0) 332 333/* Set when the variant refers to a symbol containing 334 dots or dashes. Will require explicit bracketing. */ 335#define VARIANT_BAD_BRACKETING (1 << 1) 336 337/* Set when the variant refers to a symbol which is 338 not visible from current midrule. */ 339#define VARIANT_NOT_VISIBLE_FROM_MIDRULE (1 << 2) 340 341static variant *variant_table = NULL; 342static unsigned variant_table_size = 0; 343static unsigned variant_count = 0; 344 345static variant * 346variant_table_grow (void) 347{ 348 ++variant_count; 349 if (variant_count > variant_table_size) 350 { 351 while (variant_count > variant_table_size) 352 variant_table_size = 2 * variant_table_size + 3; 353 variant_table = xnrealloc (variant_table, variant_table_size, 354 sizeof *variant_table); 355 } 356 return &variant_table[variant_count - 1]; 357} 358 359static void 360variant_table_free (void) 361{ 362 free (variant_table); 363 variant_table = NULL; 364 variant_table_size = variant_count = 0; 365} 366 367static char * 368find_prefix_end (const char *prefix, char *begin, char *end) 369{ 370 char *ptr = begin; 371 372 for (; *prefix && ptr != end; ++prefix, ++ptr) 373 if (*prefix != *ptr) 374 return 0; 375 376 if (*prefix) 377 return 0; 378 379 return ptr; 380} 381 382static variant * 383variant_add (uniqstr id, location id_loc, unsigned symbol_index, 384 char *cp, char *cp_end, bool explicit_bracketing) 385{ 386 char *prefix_end; 387 388 prefix_end = find_prefix_end (id, cp, cp_end); 389 if (prefix_end && 390 (prefix_end == cp_end || 391 (!explicit_bracketing && is_dot_or_dash (*prefix_end)))) 392 { 393 variant *r = variant_table_grow (); 394 r->symbol_index = symbol_index; 395 r->id = id; 396 r->loc = id_loc; 397 r->hidden_by = NULL; 398 r->err = 0; 399 return r; 400 } 401 else 402 return NULL; 403} 404 405static const char * 406get_at_spec (unsigned symbol_index) 407{ 408 static char at_buf[20]; 409 if (symbol_index == 0) 410 strcpy (at_buf, "$$"); 411 else 412 snprintf (at_buf, sizeof at_buf, "$%u", symbol_index); 413 return at_buf; 414} 415 416static void 417show_sub_messages (const char* cp, bool explicit_bracketing, 418 int midrule_rhs_index, char dollar_or_at, 419 bool is_warning, unsigned indent) 420{ 421 unsigned i; 422 423 for (i = 0; i < variant_count; ++i) 424 { 425 const variant *var = &variant_table[i]; 426 const char *at_spec = get_at_spec (var->symbol_index); 427 428 if (var->err == 0) 429 { 430 if (is_warning) 431 warn_at_indent (var->loc, &indent, _("refers to: %c%s at %s"), 432 dollar_or_at, var->id, at_spec); 433 else 434 complain_at_indent (var->loc, &indent, _("refers to: %c%s at %s"), 435 dollar_or_at, var->id, at_spec); 436 } 437 else 438 { 439 static struct obstack msg_buf; 440 const char *tail = explicit_bracketing ? "" : 441 cp + strlen (var->id); 442 const char *id = var->hidden_by ? var->hidden_by->id : 443 var->id; 444 location id_loc = var->hidden_by ? var->hidden_by->loc : 445 var->loc; 446 447 /* Create the explanation message. */ 448 obstack_init (&msg_buf); 449 450 obstack_printf (&msg_buf, _("possibly meant: %c"), dollar_or_at); 451 if (contains_dot_or_dash (id)) 452 obstack_printf (&msg_buf, "[%s]", id); 453 else 454 obstack_sgrow (&msg_buf, id); 455 obstack_sgrow (&msg_buf, tail); 456 457 if (var->err & VARIANT_HIDDEN) 458 { 459 obstack_printf (&msg_buf, _(", hiding %c"), dollar_or_at); 460 if (contains_dot_or_dash (var->id)) 461 obstack_printf (&msg_buf, "[%s]", var->id); 462 else 463 obstack_sgrow (&msg_buf, var->id); 464 obstack_sgrow (&msg_buf, tail); 465 } 466 467 obstack_printf (&msg_buf, _(" at %s"), at_spec); 468 469 if (var->err & VARIANT_NOT_VISIBLE_FROM_MIDRULE) 470 { 471 const char *format = 472 _(", cannot be accessed from mid-rule action at $%d"); 473 obstack_printf (&msg_buf, format, midrule_rhs_index); 474 } 475 476 obstack_1grow (&msg_buf, '\0'); 477 if (is_warning) 478 warn_at_indent (id_loc, &indent, "%s", 479 (char *) obstack_finish (&msg_buf)); 480 else 481 complain_at_indent (id_loc, &indent, "%s", 482 (char *) obstack_finish (&msg_buf)); 483 obstack_free (&msg_buf, 0); 484 } 485 } 486} 487 488/* Returned from "parse_ref" when the reference 489 is inappropriate. */ 490#define INVALID_REF (INT_MIN) 491 492/* Returned from "parse_ref" when the reference 493 points to LHS ($$) of the current rule or midrule. */ 494#define LHS_REF (INT_MIN + 1) 495 496/* Parse named or positional reference. In case of positional 497 references, can return negative values for $-n "deep" stack 498 accesses. */ 499static long int 500parse_ref (char *cp, symbol_list *rule, int rule_length, 501 int midrule_rhs_index, char *text, location text_loc, 502 char dollar_or_at) 503{ 504 symbol_list *l; 505 char *cp_end; 506 bool explicit_bracketing; 507 unsigned i; 508 unsigned valid_variants = 0; 509 unsigned valid_variant_index = 0; 510 511 if ('$' == *cp) 512 return LHS_REF; 513 514 if (c_isdigit (*cp) || (*cp == '-' && c_isdigit (* (cp + 1)))) 515 { 516 long int num = strtol (cp, &cp, 10); 517 if (1 - INT_MAX + rule_length <= num && num <= rule_length) 518 return num; 519 else 520 { 521 complain_at (text_loc, _("integer out of range: %s"), 522 quote (text)); 523 return INVALID_REF; 524 } 525 } 526 527 if ('[' == *cp) 528 { 529 /* Ignore the brackets. */ 530 char *p; 531 for (p = ++cp; *p != ']'; ++p) 532 continue; 533 cp_end = p; 534 535 explicit_bracketing = true; 536 } 537 else 538 { 539 /* Take all characters of the name. */ 540 char* p; 541 for (p = cp; *p; ++p) 542 if (is_dot_or_dash (*p)) 543 { 544 ref_tail_fields = p; 545 break; 546 } 547 for (p = cp; *p; ++p) 548 continue; 549 cp_end = p; 550 551 explicit_bracketing = false; 552 } 553 554 /* Add all relevant variants. */ 555 { 556 unsigned symbol_index; 557 variant_count = 0; 558 for (symbol_index = 0, l = rule; !symbol_list_null (l); 559 ++symbol_index, l = l->next) 560 { 561 variant *var; 562 if (l->content_type != SYMLIST_SYMBOL) 563 continue; 564 565 var = variant_add (l->content.sym->tag, l->sym_loc, 566 symbol_index, cp, cp_end, explicit_bracketing); 567 if (var && l->named_ref) 568 var->hidden_by = l->named_ref; 569 570 if (l->named_ref) 571 variant_add (l->named_ref->id, l->named_ref->loc, 572 symbol_index, cp, cp_end, explicit_bracketing); 573 } 574 } 575 576 /* Check errors. */ 577 for (i = 0; i < variant_count; ++i) 578 { 579 variant *var = &variant_table[i]; 580 unsigned symbol_index = var->symbol_index; 581 582 /* Check visibility from mid-rule actions. */ 583 if (midrule_rhs_index != 0 584 && (symbol_index == 0 || midrule_rhs_index < symbol_index)) 585 var->err |= VARIANT_NOT_VISIBLE_FROM_MIDRULE; 586 587 /* Check correct bracketing. */ 588 if (!explicit_bracketing && contains_dot_or_dash (var->id)) 589 var->err |= VARIANT_BAD_BRACKETING; 590 591 /* Check using of hidden symbols. */ 592 if (var->hidden_by) 593 var->err |= VARIANT_HIDDEN; 594 595 if (!var->err) 596 { 597 valid_variant_index = i; 598 ++valid_variants; 599 } 600 } 601 602 switch (valid_variants) 603 { 604 case 0: 605 { 606 unsigned len = (explicit_bracketing || !ref_tail_fields) ? 607 cp_end - cp : ref_tail_fields - cp; 608 unsigned indent = 0; 609 610 complain_at_indent (text_loc, &indent, _("invalid reference: %s"), 611 quote (text)); 612 indent += SUB_INDENT; 613 if (len == 0) 614 { 615 location sym_loc = text_loc; 616 sym_loc.start.column += 1; 617 sym_loc.end = sym_loc.start; 618 const char *format = 619 _("syntax error after '%c', expecting integer, letter," 620 " '_', '[', or '$'"); 621 complain_at_indent (sym_loc, &indent, format, dollar_or_at); 622 } 623 else if (midrule_rhs_index) 624 { 625 const char *format = 626 _("symbol not found in production before $%d: %.*s"); 627 complain_at_indent (rule->location, &indent, format, 628 midrule_rhs_index, len, cp); 629 } 630 else 631 { 632 const char *format = 633 _("symbol not found in production: %.*s"); 634 complain_at_indent (rule->location, &indent, format, 635 len, cp); 636 } 637 638 if (variant_count > 0) 639 show_sub_messages (cp, explicit_bracketing, midrule_rhs_index, 640 dollar_or_at, false, indent); 641 return INVALID_REF; 642 } 643 case 1: 644 { 645 unsigned indent = 0; 646 if (variant_count > 1) 647 { 648 warn_at_indent (text_loc, &indent, _("misleading reference: %s"), 649 quote (text)); 650 show_sub_messages (cp, explicit_bracketing, midrule_rhs_index, 651 dollar_or_at, true, indent + SUB_INDENT); 652 } 653 { 654 unsigned symbol_index = 655 variant_table[valid_variant_index].symbol_index; 656 return (symbol_index == midrule_rhs_index) ? LHS_REF : symbol_index; 657 } 658 } 659 case 2: 660 default: 661 { 662 unsigned indent = 0; 663 complain_at_indent (text_loc, &indent, _("ambiguous reference: %s"), 664 quote (text)); 665 show_sub_messages (cp, explicit_bracketing, midrule_rhs_index, 666 dollar_or_at, false, indent + SUB_INDENT); 667 return INVALID_REF; 668 } 669 } 670 671 /* Not reachable. */ 672 return INVALID_REF; 673} 674 675/* Keeps track of the maximum number of semantic values to the left of 676 a handle (those referenced by $0, $-1, etc.) are required by the 677 semantic actions of this grammar. */ 678int max_left_semantic_context = 0; 679 680 681/* If CP points to a typename (i.e., <.*?>), set TYPE_NAME to its 682 beginning (i.e., after the opening "<", and return the pointer 683 immediately after it. */ 684 685static 686char * 687fetch_type_name (char *cp, char const **type_name, 688 location dollar_loc) 689{ 690 if (*cp == '<') 691 { 692 *type_name = ++cp; 693 while (*cp != '>') 694 ++cp; 695 696 /* The '>' symbol will be later replaced by '\0'. Original 697 'text' is needed for error messages. */ 698 ++cp; 699 if (untyped_var_seen) 700 complain_at (dollar_loc, _("explicit type given in untyped grammar")); 701 tag_seen = true; 702 } 703 return cp; 704} 705 706/*------------------------------------------------------------------. 707| TEXT is pointing to a wannabee semantic value (i.e., a '$'). | 708| | 709| Possible inputs: $[<TYPENAME>]($|integer) | 710| | 711| Output to OBSTACK_FOR_STRING a reference to this semantic value. | 712`------------------------------------------------------------------*/ 713 714static void 715handle_action_dollar (symbol_list *rule, char *text, location dollar_loc) 716{ 717 char const *type_name = NULL; 718 char *cp = text + 1; 719 symbol_list *effective_rule; 720 int effective_rule_length; 721 int n; 722 723 if (rule->midrule_parent_rule) 724 { 725 effective_rule = rule->midrule_parent_rule; 726 effective_rule_length = rule->midrule_parent_rhs_index - 1; 727 } 728 else 729 { 730 effective_rule = rule; 731 effective_rule_length = symbol_list_length (rule->next); 732 } 733 734 /* Get the type name if explicit. */ 735 cp = fetch_type_name (cp, &type_name, dollar_loc); 736 737 n = parse_ref (cp, effective_rule, effective_rule_length, 738 rule->midrule_parent_rhs_index, text, dollar_loc, '$'); 739 740 /* End type_name. */ 741 if (type_name) 742 cp[-1] = '\0'; 743 744 switch (n) 745 { 746 case INVALID_REF: 747 break; 748 749 case LHS_REF: 750 if (!type_name) 751 type_name = symbol_list_n_type_name_get (rule, dollar_loc, 0); 752 753 if (!type_name) 754 { 755 if (union_seen | tag_seen) 756 { 757 if (rule->midrule_parent_rule) 758 complain_at (dollar_loc, 759 _("$$ for the midrule at $%d of %s" 760 " has no declared type"), 761 rule->midrule_parent_rhs_index, 762 quote (effective_rule->content.sym->tag)); 763 else 764 complain_at (dollar_loc, _("$$ of %s has no declared type"), 765 quote (rule->content.sym->tag)); 766 } 767 else 768 untyped_var_seen = true; 769 } 770 771 obstack_sgrow (&obstack_for_string, "]b4_lhs_value("); 772 obstack_quote (&obstack_for_string, type_name); 773 obstack_sgrow (&obstack_for_string, ")["); 774 rule->action_props.is_value_used = true; 775 break; 776 777 default: 778 if (max_left_semantic_context < 1 - n) 779 max_left_semantic_context = 1 - n; 780 if (!type_name && 0 < n) 781 type_name = 782 symbol_list_n_type_name_get (effective_rule, dollar_loc, n); 783 if (!type_name) 784 { 785 if (union_seen | tag_seen) 786 complain_at (dollar_loc, _("$%s of %s has no declared type"), 787 cp, quote (effective_rule->content.sym->tag)); 788 else 789 untyped_var_seen = true; 790 } 791 792 obstack_printf (&obstack_for_string, 793 "]b4_rhs_value(%d, %d, ", effective_rule_length, n); 794 obstack_quote (&obstack_for_string, type_name); 795 obstack_sgrow (&obstack_for_string, ")["); 796 if (n > 0) 797 symbol_list_n_get (effective_rule, n)->action_props.is_value_used = 798 true; 799 break; 800 } 801} 802 803 804/*------------------------------------------------------. 805| TEXT is a location token (i.e., a '@...'). Output to | 806| OBSTACK_FOR_STRING a reference to this location. | 807`------------------------------------------------------*/ 808 809static void 810handle_action_at (symbol_list *rule, char *text, location at_loc) 811{ 812 char *cp = text + 1; 813 symbol_list *effective_rule; 814 int effective_rule_length; 815 int n; 816 817 if (rule->midrule_parent_rule) 818 { 819 effective_rule = rule->midrule_parent_rule; 820 effective_rule_length = rule->midrule_parent_rhs_index - 1; 821 } 822 else 823 { 824 effective_rule = rule; 825 effective_rule_length = symbol_list_length (rule->next); 826 } 827 828 locations_flag = true; 829 830 n = parse_ref (cp, effective_rule, effective_rule_length, 831 rule->midrule_parent_rhs_index, text, at_loc, '@'); 832 switch (n) 833 { 834 case INVALID_REF: 835 break; 836 837 case LHS_REF: 838 obstack_sgrow (&obstack_for_string, "]b4_lhs_location["); 839 break; 840 841 default: 842 obstack_printf (&obstack_for_string, "]b4_rhs_location(%d, %d)[", 843 effective_rule_length, n); 844 break; 845 } 846} 847 848 849/*-------------------------. 850| Initialize the scanner. | 851`-------------------------*/ 852 853/* Translate the dollars and ats in \a self, in the context \a sc_context 854 (SC_RULE_ACTION, SC_SYMBOL_ACTION, INITIAL). */ 855 856static char const * 857translate_action (code_props *self, int sc_context) 858{ 859 char *res; 860 static bool initialized = false; 861 if (!initialized) 862 { 863 obstack_init (&obstack_for_string); 864 yy_flex_debug = 0; 865 initialized = true; 866 } 867 868 loc->start = loc->end = self->location.start; 869 yy_switch_to_buffer (yy_scan_string (self->code)); 870 res = code_lex (self, sc_context); 871 yy_delete_buffer (YY_CURRENT_BUFFER); 872 873 return res; 874} 875 876/*------------------------------------------------------------------------. 877| Implementation of the public interface as documented in "scan-code.h". | 878`------------------------------------------------------------------------*/ 879 880void 881code_props_none_init (code_props *self) 882{ 883 *self = code_props_none; 884} 885 886code_props const code_props_none = CODE_PROPS_NONE_INIT; 887 888void 889code_props_plain_init (code_props *self, char const *code, 890 location code_loc) 891{ 892 self->kind = CODE_PROPS_PLAIN; 893 self->code = code; 894 self->location = code_loc; 895 self->is_value_used = false; 896 self->rule = NULL; 897 self->named_ref = NULL; 898} 899 900void 901code_props_symbol_action_init (code_props *self, char const *code, 902 location code_loc) 903{ 904 self->kind = CODE_PROPS_SYMBOL_ACTION; 905 self->code = code; 906 self->location = code_loc; 907 self->is_value_used = false; 908 self->rule = NULL; 909 self->named_ref = NULL; 910} 911 912void 913code_props_rule_action_init (code_props *self, char const *code, 914 location code_loc, symbol_list *rule, 915 named_ref *name) 916{ 917 self->kind = CODE_PROPS_RULE_ACTION; 918 self->code = code; 919 self->location = code_loc; 920 self->is_value_used = false; 921 self->rule = rule; 922 self->named_ref = name; 923} 924 925void 926code_props_translate_code (code_props *self) 927{ 928 switch (self->kind) 929 { 930 case CODE_PROPS_NONE: 931 break; 932 case CODE_PROPS_PLAIN: 933 self->code = translate_action (self, INITIAL); 934 break; 935 case CODE_PROPS_SYMBOL_ACTION: 936 self->code = translate_action (self, SC_SYMBOL_ACTION); 937 break; 938 case CODE_PROPS_RULE_ACTION: 939 self->code = translate_action (self, SC_RULE_ACTION); 940 break; 941 } 942} 943 944void 945code_scanner_last_string_free (void) 946{ 947 STRING_FREE; 948} 949 950void 951code_scanner_free (void) 952{ 953 obstack_free (&obstack_for_string, 0); 954 variant_table_free (); 955 956 /* Reclaim Flex's buffers. */ 957 yylex_destroy (); 958} 959