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
contains_dot_or_dash(const char * p)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 *
variant_table_grow(void)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
variant_table_free(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 *
find_prefix_end(const char * prefix,char * begin,char * end)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 *
variant_add(uniqstr id,location id_loc,unsigned symbol_index,char * cp,char * cp_end,bool explicit_bracketing)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 *
get_at_spec(unsigned symbol_index)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
show_sub_messages(const char * cp,bool explicit_bracketing,int midrule_rhs_index,char dollar_or_at,bool is_warning,unsigned indent)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
parse_ref(char * cp,symbol_list * rule,int rule_length,int midrule_rhs_index,char * text,location text_loc,char dollar_or_at)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 *
fetch_type_name(char * cp,char const ** type_name,location dollar_loc)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
handle_action_dollar(symbol_list * rule,char * text,location dollar_loc)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
handle_action_at(symbol_list * rule,char * text,location at_loc)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 *
translate_action(code_props * self,int sc_context)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
code_props_none_init(code_props * self)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
code_props_plain_init(code_props * self,char const * code,location code_loc)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
code_props_symbol_action_init(code_props * self,char const * code,location code_loc)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
code_props_rule_action_init(code_props * self,char const * code,location code_loc,symbol_list * rule,named_ref * name)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
code_props_translate_code(code_props * self)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
code_scanner_last_string_free(void)945 code_scanner_last_string_free (void)
946 {
947   STRING_FREE;
948 }
949 
950 void
code_scanner_free(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