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