Home | History | Annotate | Download | only in src
      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)
     45 YY_DECL;
     46 
     47 #define YY_USER_ACTION  location_compute (loc, &loc->end, yytext, yyleng);
     48 
     49 static char *fetch_type_name (char *cp, char const **type_name,
     50                               location dollar_loc);
     51 
     52 static void handle_action_dollar (symbol_list *rule, char *cp,
     53 				  location dollar_loc);
     54 static 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. */
     57 static char *ref_tail_fields;
     58 
     59 static location the_location;
     60 static location *loc = &the_location;
     61 
     62 /* A string representing the most recent translation.  */
     63 static char *last_string;
     64 
     65 /* True if an untyped $$ or $n was seen.  */
     66 static 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.  */
     81 tag	 [^\0\n>]+
     82 
     83 /* Zero or more instances of backslash-newline.  Following GCC, allow
     84    white space between the backslash and the newline.  */
     85 splice	 (\\[ \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". */
     90 letter	  [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
     91 id	  {letter}({letter}|[-0-9])*
     92 ref      -?[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 
    296 static inline bool
    297 is_dot_or_dash (char ch)
    298 {
    299   return ch == '.' || ch == '-';
    300 }
    301 
    302 static inline bool
    303 contains_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. */
    312 typedef 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 
    341 static variant *variant_table = NULL;
    342 static unsigned variant_table_size = 0;
    343 static unsigned variant_count = 0;
    344 
    345 static variant *
    346 variant_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 
    359 static void
    360 variant_table_free (void)
    361 {
    362   free (variant_table);
    363   variant_table = NULL;
    364   variant_table_size = variant_count = 0;
    365 }
    366 
    367 static char *
    368 find_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 
    382 static variant *
    383 variant_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 
    405 static const char *
    406 get_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 
    416 static void
    417 show_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. */
    499 static long int
    500 parse_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. */
    678 int 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 
    685 static
    686 char *
    687 fetch_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 
    714 static void
    715 handle_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 
    809 static void
    810 handle_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 
    856 static char const *
    857 translate_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 
    880 void
    881 code_props_none_init (code_props *self)
    882 {
    883   *self = code_props_none;
    884 }
    885 
    886 code_props const code_props_none = CODE_PROPS_NONE_INIT;
    887 
    888 void
    889 code_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 
    900 void
    901 code_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 
    912 void
    913 code_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 
    925 void
    926 code_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 
    944 void
    945 code_scanner_last_string_free (void)
    946 {
    947   STRING_FREE;
    948 }
    949 
    950 void
    951 code_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