]> git.saurik.com Git - bison.git/blame - src/scan-code.l
hash: check insertion for memory exhaustion.
[bison.git] / src / scan-code.l
CommitLineData
e9071366
AD
1/* Bison Action Scanner -*- C -*-
2
14da0cdd 3 Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
e9071366
AD
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
f16b0819 7 This program is free software: you can redistribute it and/or modify
e9071366 8 it under the terms of the GNU General Public License as published by
f16b0819 9 the Free Software Foundation, either version 3 of the License, or
e9071366
AD
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
f16b0819 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
e9071366
AD
19
20%option debug nodefault 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"
f9bfc42a
JD
31
32#include "complain.h"
e9071366
AD
33#include "reader.h"
34#include "getargs.h"
e9071366
AD
35#include <get-errno.h>
36#include <quote.h>
37
38#include "scan-code.h"
28e52c0d 39#include "symlist.h"
e9071366
AD
40
41/* The current calling start condition: SC_RULE_ACTION or
42 SC_SYMBOL_ACTION. */
28e52c0d 43# define YY_DECL static char *code_lex (code_props *self, int sc_context)
e9071366
AD
44YY_DECL;
45
46#define YY_USER_ACTION location_compute (loc, &loc->end, yytext, yyleng);
47
4210cd0b
JD
48static void handle_action_dollar (symbol_list *rule, char *cp,
49 location dollar_loc);
50static void handle_action_at (symbol_list *rule, char *cp, location at_loc);
e9071366
AD
51static location the_location;
52static location *loc = &the_location;
ddc8ede1 53
28e52c0d
JD
54/* A string representing the most recent translation. */
55static char *last_string;
56
ddc8ede1
PE
57/* True if an untyped $$ or $n was seen. */
58static bool untyped_var_seen;
e9071366
AD
59%}
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
67
68
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. */
72tag [^\0\n>]+
73
74/* Zero or more instances of backslash-newline. Following GCC, allow
75 white space between the backslash and the newline. */
76splice (\\[ \f\t\v]*\n)*
77
78%%
79
80%{
2346344a 81 /* Nesting level of the current code in braces. */
4f82b42a 82 int braces_level = 0;
2346344a 83
42f4393a
DJ
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;
91
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;
96
e9071366
AD
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. */
4f82b42a
PE
100 aver (sc_context == SC_SYMBOL_ACTION
101 || sc_context == SC_RULE_ACTION
102 || sc_context == INITIAL);
e9071366
AD
103 BEGIN sc_context;
104%}
105
106 /*------------------------------------------------------------.
107 | Scanning a C comment. The initial `/ *' is already eaten. |
108 `------------------------------------------------------------*/
109
110<SC_COMMENT>
111{
112 "*"{splice}"/" STRING_GROW; BEGIN sc_context;
113}
114
115
116 /*--------------------------------------------------------------.
117 | Scanning a line comment. The initial `//' is already eaten. |
118 `--------------------------------------------------------------*/
119
120<SC_LINE_COMMENT>
121{
122 "\n" STRING_GROW; BEGIN sc_context;
123 {splice} STRING_GROW;
124}
125
126
127 /*--------------------------------------------.
128 | Scanning user-code characters and strings. |
129 `--------------------------------------------*/
130
131<SC_CHARACTER,SC_STRING>
132{
133 {splice}|\\{splice}. STRING_GROW;
134}
135
136<SC_CHARACTER>
137{
138 "'" STRING_GROW; BEGIN sc_context;
139}
140
141<SC_STRING>
142{
143 "\"" STRING_GROW; BEGIN sc_context;
144}
145
146
147<SC_RULE_ACTION,SC_SYMBOL_ACTION>{
148 "'" {
149 STRING_GROW;
150 BEGIN SC_CHARACTER;
42f4393a 151 need_semicolon = true;
e9071366
AD
152 }
153 "\"" {
154 STRING_GROW;
155 BEGIN SC_STRING;
42f4393a 156 need_semicolon = true;
e9071366
AD
157 }
158 "/"{splice}"*" {
159 STRING_GROW;
160 BEGIN SC_COMMENT;
161 }
162 "/"{splice}"/" {
163 STRING_GROW;
164 BEGIN SC_LINE_COMMENT;
165 }
166}
167
168<SC_RULE_ACTION>
169{
28e52c0d
JD
170 "$"("<"{tag}">")?(-?[0-9]+|"$") {
171 handle_action_dollar (self->rule, yytext, *loc);
42f4393a 172 need_semicolon = true;
28e52c0d
JD
173 }
174 "@"(-?[0-9]+|"$") {
175 handle_action_at (self->rule, yytext, *loc);
42f4393a 176 need_semicolon = true;
28e52c0d 177 }
e9071366
AD
178
179 "$" {
180 warn_at (*loc, _("stray `$'"));
181 obstack_sgrow (&obstack_for_string, "$][");
42f4393a 182 need_semicolon = true;
e9071366
AD
183 }
184 "@" {
185 warn_at (*loc, _("stray `@'"));
186 obstack_sgrow (&obstack_for_string, "@@");
42f4393a
DJ
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;
e9071366 196 }
2346344a 197
42f4393a
DJ
198 ";" STRING_GROW; need_semicolon = false;
199 "{" STRING_GROW; ++braces_level; need_semicolon = false;
2346344a 200 "}" {
14da0cdd 201 bool outer_brace = --braces_level == 0;
2346344a
AD
202
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
42f4393a 206 not append one. */
7ed73f82 207 if (outer_brace && !yacc_flag && language_prio == default_prio
42f4393a
DJ
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 }
2346344a
AD
214
215 STRING_GROW;
42f4393a 216 need_semicolon = false;
2346344a 217 }
42f4393a
DJ
218
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;
224
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;
e9071366
AD
229}
230
231<SC_SYMBOL_ACTION>
232{
28e52c0d
JD
233 "$$" {
234 obstack_sgrow (&obstack_for_string, "]b4_dollar_dollar[");
235 self->is_value_used = true;
236 }
e785ccf7
JD
237 "@$" {
238 obstack_sgrow (&obstack_for_string, "]b4_at_dollar[");
239 locations_flag = true;
240 }
e9071366
AD
241}
242
243
244 /*-----------------------------------------.
245 | Escape M4 quoting characters in C code. |
246 `-----------------------------------------*/
247
248<*>
249{
250 \$ obstack_sgrow (&obstack_for_string, "$][");
251 \@ obstack_sgrow (&obstack_for_string, "@@");
252 \[ obstack_sgrow (&obstack_for_string, "@{");
253 \] obstack_sgrow (&obstack_for_string, "@}");
254}
255
256 /*-----------------------------------------------------.
257 | By default, grow the string obstack with the input. |
258 `-----------------------------------------------------*/
259
260<*>.|\n STRING_GROW;
261
262 /* End of processing. */
263<*><<EOF>> {
28e52c0d
JD
264 STRING_FINISH;
265 return last_string;
e9071366
AD
266 }
267
268%%
269
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. */
273int max_left_semantic_context = 0;
274
275
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`------------------------------------------------------------------*/
283
284static void
4210cd0b 285handle_action_dollar (symbol_list *rule, char *text, location dollar_loc)
e9071366 286{
28e52c0d 287 char const *type_name = NULL;
e9071366 288 char *cp = text + 1;
ffa4ba3a
JD
289 symbol_list *effective_rule;
290 int effective_rule_length;
291
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 }
e9071366
AD
302
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;
ddc8ede1
PE
311 if (untyped_var_seen)
312 complain_at (dollar_loc, _("explicit type given in untyped grammar"));
313 tag_seen = true;
e9071366
AD
314 }
315
316 if (*cp == '$')
317 {
318 if (!type_name)
4210cd0b 319 type_name = symbol_list_n_type_name_get (rule, dollar_loc, 0);
ddc8ede1
PE
320
321 if (!type_name)
ad6b1efa 322 {
ddc8ede1
PE
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,
3be03b13 330 effective_rule->content.sym->tag);
ddc8ede1
PE
331 else
332 complain_at (dollar_loc, _("$$ of `%s' has no declared type"),
3be03b13 333 rule->content.sym->tag);
ddc8ede1 334 }
ad6b1efa 335 else
ddc8ede1
PE
336 untyped_var_seen = true;
337 type_name = "";
ad6b1efa 338 }
ddc8ede1 339
e9071366
AD
340 obstack_fgrow1 (&obstack_for_string,
341 "]b4_lhs_value([%s])[", type_name);
f6857bbf 342 rule->action_props.is_value_used = true;
e9071366
AD
343 }
344 else
345 {
ddc8ede1
PE
346 long int num = strtol (cp, NULL, 10);
347
348 if (1 - INT_MAX + effective_rule_length <= num
349 && num <= effective_rule_length)
e9071366
AD
350 {
351 int n = num;
ddc8ede1
PE
352 if (max_left_semantic_context < 1 - n)
353 max_left_semantic_context = 1 - n;
354 if (!type_name && 0 < n)
0c8e079f 355 type_name =
ffa4ba3a 356 symbol_list_n_type_name_get (effective_rule, dollar_loc, n);
e9071366 357 if (!type_name)
ddc8ede1
PE
358 {
359 if (union_seen | tag_seen)
360 complain_at (dollar_loc, _("$%d of `%s' has no declared type"),
3be03b13 361 n, effective_rule->content.sym->tag);
ddc8ede1
PE
362 else
363 untyped_var_seen = true;
364 type_name = "";
365 }
366
e9071366
AD
367 obstack_fgrow3 (&obstack_for_string,
368 "]b4_rhs_value(%d, %d, [%s])[",
ffa4ba3a 369 effective_rule_length, n, type_name);
28e52c0d 370 if (n > 0)
f6857bbf
JD
371 symbol_list_n_get (effective_rule, n)->action_props.is_value_used =
372 true;
e9071366
AD
373 }
374 else
0c8e079f 375 complain_at (dollar_loc, _("integer out of range: %s"), quote (text));
e9071366
AD
376 }
377}
378
379
380/*------------------------------------------------------.
381| TEXT is a location token (i.e., a `@...'). Output to |
382| OBSTACK_FOR_STRING a reference to this location. |
383`------------------------------------------------------*/
384
385static void
4210cd0b 386handle_action_at (symbol_list *rule, char *text, location at_loc)
e9071366
AD
387{
388 char *cp = text + 1;
4f82b42a
PE
389 int effective_rule_length =
390 (rule->midrule_parent_rule
391 ? rule->midrule_parent_rhs_index - 1
392 : symbol_list_length (rule->next));
ffa4ba3a 393
4f82b42a 394 locations_flag = true;
e9071366
AD
395
396 if (*cp == '$')
397 obstack_sgrow (&obstack_for_string, "]b4_lhs_location[");
398 else
399 {
ddc8ede1 400 long int num = strtol (cp, NULL, 10);
e9071366 401
ddc8ede1
PE
402 if (1 - INT_MAX + effective_rule_length <= num
403 && num <= effective_rule_length)
e9071366
AD
404 {
405 int n = num;
406 obstack_fgrow2 (&obstack_for_string, "]b4_rhs_location(%d, %d)[",
ffa4ba3a 407 effective_rule_length, n);
e9071366
AD
408 }
409 else
0c8e079f 410 complain_at (at_loc, _("integer out of range: %s"), quote (text));
e9071366
AD
411 }
412}
413
414
415/*-------------------------.
416| Initialize the scanner. |
417`-------------------------*/
418
28e52c0d 419/* Translate the dollars and ats in \a self, in the context \a sc_context
ddc8ede1 420 (SC_RULE_ACTION, SC_SYMBOL_ACTION, INITIAL). */
e9071366 421
eb095650 422static char const *
28e52c0d 423translate_action (code_props *self, int sc_context)
e9071366 424{
2ce4ed68 425 char *res;
e9071366
AD
426 static bool initialized = false;
427 if (!initialized)
428 {
429 obstack_init (&obstack_for_string);
e9071366
AD
430 yy_flex_debug = 0;
431 initialized = true;
432 }
433
28e52c0d
JD
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);
e9071366
AD
437 yy_delete_buffer (YY_CURRENT_BUFFER);
438
439 return res;
440}
441
28e52c0d
JD
442/*------------------------------------------------------------------------.
443| Implementation of the public interface as documented in "scan-code.h". |
444`------------------------------------------------------------------------*/
445
446void
447code_props_none_init (code_props *self)
76290368 448{
28e52c0d 449 *self = code_props_none;
76290368
JD
450}
451
28e52c0d
JD
452code_props const code_props_none = CODE_PROPS_NONE_INIT;
453
454void
455code_props_plain_init (code_props *self, char const *code, location code_loc)
76290368 456{
28e52c0d
JD
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;
76290368
JD
462}
463
28e52c0d
JD
464void
465code_props_symbol_action_init (code_props *self, char const *code,
466 location code_loc)
e9071366 467{
28e52c0d
JD
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;
e9071366
AD
473}
474
28e52c0d
JD
475void
476code_props_rule_action_init (code_props *self, char const *code,
477 location code_loc, symbol_list *rule)
478{
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;
484}
485
486void
487code_props_translate_code (code_props *self)
488{
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 }
503}
504
505void
506code_scanner_last_string_free (void)
507{
508 STRING_FREE;
509}
e9071366
AD
510
511void
512code_scanner_free (void)
513{
514 obstack_free (&obstack_for_string, 0);
515 /* Reclaim Flex's buffers. */
580b8926 516 yylex_destroy ();
e9071366 517}