rename muscle_tab.* as muscle-tab.* for consistency.
[bison/ericb.git] / src / scan-code.l
blob88f899021b6315065e137efd60dfa417f52e8c22
1 /* Bison Action Scanner                             -*- C -*-
3    Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5    This file is part of Bison, the GNU Compiler Compiler.
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.
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.
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/>.  */
20 %option debug nodefault nounput noyywrap never-interactive
21 %option prefix="code_" outfile="lex.yy.c"
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
29 #define FLEX_PREFIX(Id) code_ ## Id
30 #include <src/flex-scanner.h>
32 #include <src/complain.h>
33 #include <src/reader.h>
34 #include <src/getargs.h>
35 #include <get-errno.h>
36 #include <quote.h>
37 #include <src/muscle-tab.h>
38 #include <src/scan-code.h>
39 #include <src/symlist.h>
41 /* The current calling start condition: SC_RULE_ACTION or
42    SC_SYMBOL_ACTION. */
43 # define YY_DECL static char *code_lex (code_props *self, int sc_context)
44 YY_DECL;
46 #define YY_USER_ACTION  location_compute (loc, &loc->end, yytext, yyleng);
48 static void handle_action_dollar (symbol_list *rule, char *cp,
49                                   location dollar_loc);
50 static void handle_action_at (symbol_list *rule, char *cp, location at_loc);
51 static location the_location;
52 static location *loc = &the_location;
54 /* A string representing the most recent translation.  */
55 static char *last_string;
57 /* True if an untyped $$ or $n was seen.  */
58 static bool untyped_var_seen;
60  /* C and C++ comments in code. */
61 %x SC_COMMENT SC_LINE_COMMENT
62  /* Strings and characters in code. */
63 %x SC_STRING SC_CHARACTER
64  /* Whether in a rule or symbol action.  Specifies the translation
65     of $ and @.  */
66 %x SC_RULE_ACTION SC_SYMBOL_ACTION
69 /* POSIX says that a tag must be both an id and a C union member, but
70    historically almost any character is allowed in a tag.  We disallow
71    NUL and newline, as this simplifies our implementation.  */
72 tag      [^\0\n>]+
74 /* Zero or more instances of backslash-newline.  Following GCC, allow
75    white space between the backslash and the newline.  */
76 splice   (\\[ \f\t\v]*\n)*
81   /* Nesting level of the current code in braces.  */
82   int braces_level = 0;
84   /* Whether a semicolon is probably needed.
85      The heuristic is that a semicolon is not needed after `{', `}', `;',
86      or a C preprocessor directive, and that whitespaces and comments
87      do not affect this flag.
88      Note that `{' does not need a semicolon because of `{}'.
89      A semicolon may be needed before a cpp direcive, but don't bother.  */
90   bool need_semicolon = false;
92   /* Whether in a C preprocessor directive.  Don't use a start condition
93      for this because, at the end of strings and comments, we still need
94      to know whether we're in a directive.  */
95   bool in_cpp = false;
97   /* This scanner is special: it is invoked only once, henceforth
98      is expected to return only once.  This initialization is
99      therefore done once per action to translate. */
100   aver (sc_context == SC_SYMBOL_ACTION
101         || sc_context == SC_RULE_ACTION
102         || sc_context == INITIAL);
103   BEGIN sc_context;
106   /*------------------------------------------------------------.
107   | Scanning a C comment.  The initial `/ *' is already eaten.  |
108   `------------------------------------------------------------*/
110 <SC_COMMENT>
112   "*"{splice}"/"  STRING_GROW; BEGIN sc_context;
116   /*--------------------------------------------------------------.
117   | Scanning a line comment.  The initial `//' is already eaten.  |
118   `--------------------------------------------------------------*/
120 <SC_LINE_COMMENT>
122   "\n"           STRING_GROW; BEGIN sc_context;
123   {splice}       STRING_GROW;
127   /*--------------------------------------------.
128   | Scanning user-code characters and strings.  |
129   `--------------------------------------------*/
131 <SC_CHARACTER,SC_STRING>
133   {splice}|\\{splice}.  STRING_GROW;
136 <SC_CHARACTER>
138   "'"           STRING_GROW; BEGIN sc_context;
141 <SC_STRING>
143   "\""          STRING_GROW; BEGIN sc_context;
147 <SC_RULE_ACTION,SC_SYMBOL_ACTION>{
148   "'" {
149     STRING_GROW;
150     BEGIN SC_CHARACTER;
151     need_semicolon = true;
152   }
153   "\"" {
154     STRING_GROW;
155     BEGIN SC_STRING;
156     need_semicolon = true;
157   }
158   "/"{splice}"*" {
159     STRING_GROW;
160     BEGIN SC_COMMENT;
161   }
162   "/"{splice}"/" {
163     STRING_GROW;
164     BEGIN SC_LINE_COMMENT;
165   }
168 <SC_RULE_ACTION>
170   "$"("<"{tag}">")?(-?[0-9]+|"$")  {
171     handle_action_dollar (self->rule, yytext, *loc);
172     need_semicolon = true;
173   }
174   "@"(-?[0-9]+|"$") {
175     handle_action_at (self->rule, yytext, *loc);
176     need_semicolon = true;
177   }
179   "$"  {
180     warn_at (*loc, _("stray `$'"));
181     obstack_sgrow (&obstack_for_string, "$][");
182     need_semicolon = true;
183   }
184   "@"  {
185     warn_at (*loc, _("stray `@'"));
186     obstack_sgrow (&obstack_for_string, "@@");
187     need_semicolon = true;
188   }
189   "["  {
190     obstack_sgrow (&obstack_for_string, "@{");
191     need_semicolon = true;
192   }
193   "]"  {
194     obstack_sgrow (&obstack_for_string, "@}");
195     need_semicolon = true;
196   }
198   ";"  STRING_GROW;                 need_semicolon = false;
199   "{"  STRING_GROW; ++braces_level; need_semicolon = false;
200   "}"  {
201     bool outer_brace = --braces_level == 0;
203     /* As an undocumented Bison extension, append `;' before the last
204        brace in braced code, so that the user code can omit trailing
205        `;'.  But do not append `;' if emulating Yacc, since Yacc does
206        not append one.  */
207     if (outer_brace && !yacc_flag && language_prio == default_prio
208         && skeleton_prio == default_prio && need_semicolon && ! in_cpp)
209       {
210         warn_at (*loc, _("a `;' might be needed at the end of action code"));
211         warn_at (*loc, _("future versions of Bison will not add the `;'"));
212         obstack_1grow (&obstack_for_string, ';');
213       }
215     STRING_GROW;
216     need_semicolon = false;
217   }
219   /* Preprocessing directives should only be recognized at the beginning
220      of lines, allowing whitespace including comments, but in C/C++,
221      `#' can only be the start of preprocessor directives or within
222      `#define' directives anyway, so don't bother with begin of line.  */
223   "#"       STRING_GROW; in_cpp = true;
225   {splice}  STRING_GROW;
226   [\n\r]    STRING_GROW; if (in_cpp) in_cpp = need_semicolon = false;
227   [ \t\f]   STRING_GROW;
228   .         STRING_GROW; need_semicolon = true;
231 <SC_SYMBOL_ACTION>
233   "$$" {
234     obstack_sgrow (&obstack_for_string, "]b4_dollar_dollar[");
235     self->is_value_used = true;
236   }
237   "@$" {
238     obstack_sgrow (&obstack_for_string, "]b4_at_dollar[");
239     muscle_percent_define_ensure("locations", the_location, true);
240   }
244   /*-----------------------------------------.
245   | Escape M4 quoting characters in C code.  |
246   `-----------------------------------------*/
250   \$    obstack_sgrow (&obstack_for_string, "$][");
251   \@    obstack_sgrow (&obstack_for_string, "@@");
252   \[    obstack_sgrow (&obstack_for_string, "@{");
253   \]    obstack_sgrow (&obstack_for_string, "@}");
256   /*-----------------------------------------------------.
257   | By default, grow the string obstack with the input.  |
258   `-----------------------------------------------------*/
260 <*>.|\n STRING_GROW;
262  /* End of processing. */
263 <*><<EOF>>       {
264                    STRING_FINISH;
265                    return last_string;
266                  }
270 /* Keeps track of the maximum number of semantic values to the left of
271    a handle (those referenced by $0, $-1, etc.) are required by the
272    semantic actions of this grammar. */
273 int max_left_semantic_context = 0;
276 /*------------------------------------------------------------------.
277 | TEXT is pointing to a wannabee semantic value (i.e., a `$').      |
278 |                                                                   |
279 | Possible inputs: $[<TYPENAME>]($|integer)                         |
280 |                                                                   |
281 | Output to OBSTACK_FOR_STRING a reference to this semantic value.  |
282 `------------------------------------------------------------------*/
284 static void
285 handle_action_dollar (symbol_list *rule, char *text, location dollar_loc)
287   char const *type_name = NULL;
288   char *cp = text + 1;
289   symbol_list *effective_rule;
290   int effective_rule_length;
292   if (rule->midrule_parent_rule)
293     {
294       effective_rule = rule->midrule_parent_rule;
295       effective_rule_length = rule->midrule_parent_rhs_index - 1;
296     }
297   else
298     {
299       effective_rule = rule;
300       effective_rule_length = symbol_list_length (rule->next);
301     }
303   /* Get the type name if explicit. */
304   if (*cp == '<')
305     {
306       type_name = ++cp;
307       while (*cp != '>')
308         ++cp;
309       *cp = '\0';
310       ++cp;
311       if (untyped_var_seen)
312         complain_at (dollar_loc, _("explicit type given in untyped grammar"));
313       tag_seen = true;
314     }
316   if (*cp == '$')
317     {
318       if (!type_name)
319         type_name = symbol_list_n_type_name_get (rule, dollar_loc, 0);
321       if (!type_name)
322         {
323           if (union_seen | tag_seen)
324             {
325               if (rule->midrule_parent_rule)
326                 complain_at (dollar_loc,
327                              _("$$ for the midrule at $%d of `%s'"
328                                " has no declared type"),
329                              rule->midrule_parent_rhs_index,
330                              effective_rule->content.sym->tag);
331               else
332                 complain_at (dollar_loc, _("$$ of `%s' has no declared type"),
333                              rule->content.sym->tag);
334             }
335           else
336             untyped_var_seen = true;
337           type_name = "";
338         }
340       obstack_fgrow1 (&obstack_for_string,
341                       "]b4_lhs_value([%s])[", type_name);
342       rule->action_props.is_value_used = true;
343     }
344   else
345     {
346       long int num = strtol (cp, NULL, 10);
348       if (1 - INT_MAX + effective_rule_length <= num
349           && num <= effective_rule_length)
350         {
351           int n = num;
352           if (max_left_semantic_context < 1 - n)
353             max_left_semantic_context = 1 - n;
354           if (!type_name && 0 < n)
355             type_name =
356               symbol_list_n_type_name_get (effective_rule, dollar_loc, n);
357           if (!type_name)
358             {
359               if (union_seen | tag_seen)
360                 complain_at (dollar_loc, _("$%d of `%s' has no declared type"),
361                              n, effective_rule->content.sym->tag);
362               else
363                 untyped_var_seen = true;
364               type_name = "";
365             }
367           obstack_fgrow3 (&obstack_for_string,
368                           "]b4_rhs_value(%d, %d, [%s])[",
369                           effective_rule_length, n, type_name);
370           if (n > 0)
371             symbol_list_n_get (effective_rule, n)->action_props.is_value_used =
372               true;
373         }
374       else
375         complain_at (dollar_loc, _("integer out of range: %s"), quote (text));
376     }
380 /*------------------------------------------------------.
381 | TEXT is a location token (i.e., a `@...').  Output to |
382 | OBSTACK_FOR_STRING a reference to this location.      |
383 `------------------------------------------------------*/
385 static void
386 handle_action_at (symbol_list *rule, char *text, location at_loc)
388   char *cp = text + 1;
389   int effective_rule_length =
390     (rule->midrule_parent_rule
391      ? rule->midrule_parent_rhs_index - 1
392      : symbol_list_length (rule->next));
394   muscle_percent_define_ensure("locations", at_loc, true);
396   if (*cp == '$')
397     obstack_sgrow (&obstack_for_string, "]b4_lhs_location[");
398   else
399     {
400       long int num = strtol (cp, NULL, 10);
402       if (1 - INT_MAX + effective_rule_length <= num
403           && num <= effective_rule_length)
404         {
405           int n = num;
406           obstack_fgrow2 (&obstack_for_string, "]b4_rhs_location(%d, %d)[",
407                           effective_rule_length, n);
408         }
409       else
410         complain_at (at_loc, _("integer out of range: %s"), quote (text));
411     }
415 /*-------------------------.
416 | Initialize the scanner.  |
417 `-------------------------*/
419 /* Translate the dollars and ats in \a self, in the context \a sc_context
420    (SC_RULE_ACTION, SC_SYMBOL_ACTION, INITIAL).  */
422 static char const *
423 translate_action (code_props *self, int sc_context)
425   char *res;
426   static bool initialized = false;
427   if (!initialized)
428     {
429       obstack_init (&obstack_for_string);
430       yy_flex_debug = 0;
431       initialized = true;
432     }
434   loc->start = loc->end = self->location.start;
435   yy_switch_to_buffer (yy_scan_string (self->code));
436   res = code_lex (self, sc_context);
437   yy_delete_buffer (YY_CURRENT_BUFFER);
439   return res;
442 /*------------------------------------------------------------------------.
443 | Implementation of the public interface as documented in "scan-code.h".  |
444 `------------------------------------------------------------------------*/
446 void
447 code_props_none_init (code_props *self)
449   *self = code_props_none;
452 code_props const code_props_none = CODE_PROPS_NONE_INIT;
454 void
455 code_props_plain_init (code_props *self, char const *code, location code_loc)
457   self->kind = CODE_PROPS_PLAIN;
458   self->code = code;
459   self->location = code_loc;
460   self->is_value_used = false;
461   self->rule = NULL;
464 void
465 code_props_symbol_action_init (code_props *self, char const *code,
466                                location code_loc)
468   self->kind = CODE_PROPS_SYMBOL_ACTION;
469   self->code = code;
470   self->location = code_loc;
471   self->is_value_used = false;
472   self->rule = NULL;
475 void
476 code_props_rule_action_init (code_props *self, char const *code,
477                              location code_loc, symbol_list *rule)
479   self->kind = CODE_PROPS_RULE_ACTION;
480   self->code = code;
481   self->location = code_loc;
482   self->is_value_used = false;
483   self->rule = rule;
486 void
487 code_props_translate_code (code_props *self)
489   switch (self->kind)
490     {
491       case CODE_PROPS_NONE:
492         break;
493       case CODE_PROPS_PLAIN:
494         self->code = translate_action (self, INITIAL);
495         break;
496       case CODE_PROPS_SYMBOL_ACTION:
497         self->code = translate_action (self, SC_SYMBOL_ACTION);
498         break;
499       case CODE_PROPS_RULE_ACTION:
500         self->code = translate_action (self, SC_RULE_ACTION);
501         break;
502     }
505 void
506 code_scanner_last_string_free (void)
508   STRING_FREE;
511 void
512 code_scanner_free (void)
514   obstack_free (&obstack_for_string, 0);
515   /* Reclaim Flex's buffers.  */
516   yylex_destroy ();