]> git.saurik.com Git - bison.git/blob - src/scan-code.l
i18n: fix for gnulib.
[bison.git] / src / scan-code.l
1 /* Bison Action Scanner -*- C -*-
2
3 Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software
4 Foundation, Inc.
5
6 This file is part of Bison, the GNU Compiler Compiler.
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21 %option debug nodefault noinput nounput noyywrap never-interactive
22 %option prefix="code_" outfile="lex.yy.c"
23
24 %{
25 /* Work around a bug in flex 2.5.31. See Debian bug 333231
26 <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>. */
27 #undef code_wrap
28 #define code_wrap() 1
29
30 #define FLEX_PREFIX(Id) code_ ## Id
31 #include "flex-scanner.h"
32
33 #include "complain.h"
34 #include "reader.h"
35 #include "getargs.h"
36 #include <get-errno.h>
37 #include <quote.h>
38
39 #include "scan-code.h"
40 #include "symlist.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 void handle_action_dollar (symbol_list *rule, char *cp,
50 location dollar_loc);
51 static void handle_action_at (symbol_list *rule, char *cp, location at_loc);
52 static location the_location;
53 static location *loc = &the_location;
54
55 /* A string representing the most recent translation. */
56 static char *last_string;
57
58 /* True if an untyped $$ or $n was seen. */
59 static bool untyped_var_seen;
60 %}
61 /* C and C++ comments in code. */
62 %x SC_COMMENT SC_LINE_COMMENT
63 /* Strings and characters in code. */
64 %x SC_STRING SC_CHARACTER
65 /* Whether in a rule or symbol action. Specifies the translation
66 of $ and @. */
67 %x SC_RULE_ACTION SC_SYMBOL_ACTION
68
69
70 /* POSIX says that a tag must be both an id and a C union member, but
71 historically almost any character is allowed in a tag. We disallow
72 NUL and newline, as this simplifies our implementation. */
73 tag [^\0\n>]+
74
75 /* Zero or more instances of backslash-newline. Following GCC, allow
76 white space between the backslash and the newline. */
77 splice (\\[ \f\t\v]*\n)*
78
79 %%
80
81 %{
82 /* Nesting level of the current code in braces. */
83 int braces_level = 0;
84
85 /* This scanner is special: it is invoked only once, henceforth
86 is expected to return only once. This initialization is
87 therefore done once per action to translate. */
88 aver (sc_context == SC_SYMBOL_ACTION
89 || sc_context == SC_RULE_ACTION
90 || sc_context == INITIAL);
91 BEGIN sc_context;
92 %}
93
94 /*------------------------------------------------------------.
95 | Scanning a C comment. The initial `/ *' is already eaten. |
96 `------------------------------------------------------------*/
97
98 <SC_COMMENT>
99 {
100 "*"{splice}"/" STRING_GROW; BEGIN sc_context;
101 }
102
103
104 /*--------------------------------------------------------------.
105 | Scanning a line comment. The initial `//' is already eaten. |
106 `--------------------------------------------------------------*/
107
108 <SC_LINE_COMMENT>
109 {
110 "\n" STRING_GROW; BEGIN sc_context;
111 {splice} STRING_GROW;
112 }
113
114
115 /*--------------------------------------------.
116 | Scanning user-code characters and strings. |
117 `--------------------------------------------*/
118
119 <SC_CHARACTER,SC_STRING>
120 {
121 {splice}|\\{splice}. STRING_GROW;
122 }
123
124 <SC_CHARACTER>
125 {
126 "'" STRING_GROW; BEGIN sc_context;
127 }
128
129 <SC_STRING>
130 {
131 "\"" STRING_GROW; BEGIN sc_context;
132 }
133
134
135 <SC_RULE_ACTION,SC_SYMBOL_ACTION>{
136 "'" {
137 STRING_GROW;
138 BEGIN SC_CHARACTER;
139 }
140 "\"" {
141 STRING_GROW;
142 BEGIN SC_STRING;
143 }
144 "/"{splice}"*" {
145 STRING_GROW;
146 BEGIN SC_COMMENT;
147 }
148 "/"{splice}"/" {
149 STRING_GROW;
150 BEGIN SC_LINE_COMMENT;
151 }
152 }
153
154 <SC_RULE_ACTION>
155 {
156 "$"("<"{tag}">")?(-?[0-9]+|"$") {
157 handle_action_dollar (self->rule, yytext, *loc);
158 }
159 "@"(-?[0-9]+|"$") {
160 handle_action_at (self->rule, yytext, *loc);
161 }
162
163 "$" {
164 warn_at (*loc, _("stray `$'"));
165 obstack_sgrow (&obstack_for_string, "$][");
166 }
167 "@" {
168 warn_at (*loc, _("stray `@'"));
169 obstack_sgrow (&obstack_for_string, "@@");
170 }
171
172 "{" STRING_GROW; ++braces_level;
173 "}" {
174 bool outer_brace = --braces_level == 0;
175
176 /* As an undocumented Bison extension, append `;' before the last
177 brace in braced code, so that the user code can omit trailing
178 `;'. But do not append `;' if emulating Yacc, since Yacc does
179 not append one. Also, some output languages (like Java) do not
180 accept an extra semicolon, so don't append if the user specified
181 a skeleton or language.
182
183 FIXME: Bison should warn if a semicolon seems to be necessary
184 here, and should omit the semicolon if it seems unnecessary
185 (e.g., after ';', '{', or '}', each followed by comments or
186 white space). Such a warning shouldn't depend on --yacc; it
187 should depend on a new --pedantic option, which would cause
188 Bison to warn if it detects an extension to POSIX. --pedantic
189 should also diagnose other Bison extensions like %yacc.
190 Perhaps there should also be a GCC-style --pedantic-errors
191 option, so that such warnings are diagnosed as errors. */
192 if (outer_brace && !yacc_flag && language_prio == default_prio
193 && skeleton_prio == default_prio)
194 obstack_1grow (&obstack_for_string, ';');
195
196 STRING_GROW;
197 }
198 }
199
200 <SC_SYMBOL_ACTION>
201 {
202 "$$" {
203 obstack_sgrow (&obstack_for_string, "]b4_dollar_dollar[");
204 self->is_value_used = true;
205 }
206 "@$" {
207 obstack_sgrow (&obstack_for_string, "]b4_at_dollar[");
208 locations_flag = true;
209 }
210 }
211
212
213 /*-----------------------------------------.
214 | Escape M4 quoting characters in C code. |
215 `-----------------------------------------*/
216
217 <*>
218 {
219 \$ obstack_sgrow (&obstack_for_string, "$][");
220 \@ obstack_sgrow (&obstack_for_string, "@@");
221 \[ obstack_sgrow (&obstack_for_string, "@{");
222 \] obstack_sgrow (&obstack_for_string, "@}");
223 }
224
225 /*-----------------------------------------------------.
226 | By default, grow the string obstack with the input. |
227 `-----------------------------------------------------*/
228
229 <*>.|\n STRING_GROW;
230
231 /* End of processing. */
232 <*><<EOF>> {
233 STRING_FINISH;
234 return last_string;
235 }
236
237 %%
238
239 /* Keeps track of the maximum number of semantic values to the left of
240 a handle (those referenced by $0, $-1, etc.) are required by the
241 semantic actions of this grammar. */
242 int max_left_semantic_context = 0;
243
244
245 /*------------------------------------------------------------------.
246 | TEXT is pointing to a wannabee semantic value (i.e., a `$'). |
247 | |
248 | Possible inputs: $[<TYPENAME>]($|integer) |
249 | |
250 | Output to OBSTACK_FOR_STRING a reference to this semantic value. |
251 `------------------------------------------------------------------*/
252
253 static void
254 handle_action_dollar (symbol_list *rule, char *text, location dollar_loc)
255 {
256 char const *type_name = NULL;
257 char *cp = text + 1;
258 symbol_list *effective_rule;
259 int effective_rule_length;
260
261 if (rule->midrule_parent_rule)
262 {
263 effective_rule = rule->midrule_parent_rule;
264 effective_rule_length = rule->midrule_parent_rhs_index - 1;
265 }
266 else
267 {
268 effective_rule = rule;
269 effective_rule_length = symbol_list_length (rule->next);
270 }
271
272 /* Get the type name if explicit. */
273 if (*cp == '<')
274 {
275 type_name = ++cp;
276 while (*cp != '>')
277 ++cp;
278 *cp = '\0';
279 ++cp;
280 if (untyped_var_seen)
281 complain_at (dollar_loc, _("explicit type given in untyped grammar"));
282 tag_seen = true;
283 }
284
285 if (*cp == '$')
286 {
287 if (!type_name)
288 type_name = symbol_list_n_type_name_get (rule, dollar_loc, 0);
289
290 if (!type_name)
291 {
292 if (union_seen | tag_seen)
293 {
294 if (rule->midrule_parent_rule)
295 complain_at (dollar_loc,
296 _("$$ for the midrule at $%d of `%s'"
297 " has no declared type"),
298 rule->midrule_parent_rhs_index,
299 effective_rule->content.sym->tag);
300 else
301 complain_at (dollar_loc, _("$$ of `%s' has no declared type"),
302 rule->content.sym->tag);
303 }
304 else
305 untyped_var_seen = true;
306 type_name = "";
307 }
308
309 obstack_fgrow1 (&obstack_for_string,
310 "]b4_lhs_value([%s])[", type_name);
311 rule->action_props.is_value_used = true;
312 }
313 else
314 {
315 long int num = strtol (cp, NULL, 10);
316
317 if (1 - INT_MAX + effective_rule_length <= num
318 && num <= effective_rule_length)
319 {
320 int n = num;
321 if (max_left_semantic_context < 1 - n)
322 max_left_semantic_context = 1 - n;
323 if (!type_name && 0 < n)
324 type_name =
325 symbol_list_n_type_name_get (effective_rule, dollar_loc, n);
326 if (!type_name)
327 {
328 if (union_seen | tag_seen)
329 complain_at (dollar_loc, _("$%d of `%s' has no declared type"),
330 n, effective_rule->content.sym->tag);
331 else
332 untyped_var_seen = true;
333 type_name = "";
334 }
335
336 obstack_fgrow3 (&obstack_for_string,
337 "]b4_rhs_value(%d, %d, [%s])[",
338 effective_rule_length, n, type_name);
339 if (n > 0)
340 symbol_list_n_get (effective_rule, n)->action_props.is_value_used =
341 true;
342 }
343 else
344 complain_at (dollar_loc, _("integer out of range: %s"), quote (text));
345 }
346 }
347
348
349 /*------------------------------------------------------.
350 | TEXT is a location token (i.e., a `@...'). Output to |
351 | OBSTACK_FOR_STRING a reference to this location. |
352 `------------------------------------------------------*/
353
354 static void
355 handle_action_at (symbol_list *rule, char *text, location at_loc)
356 {
357 char *cp = text + 1;
358 int effective_rule_length =
359 (rule->midrule_parent_rule
360 ? rule->midrule_parent_rhs_index - 1
361 : symbol_list_length (rule->next));
362
363 locations_flag = true;
364
365 if (*cp == '$')
366 obstack_sgrow (&obstack_for_string, "]b4_lhs_location[");
367 else
368 {
369 long int num = strtol (cp, NULL, 10);
370
371 if (1 - INT_MAX + effective_rule_length <= num
372 && num <= effective_rule_length)
373 {
374 int n = num;
375 obstack_fgrow2 (&obstack_for_string, "]b4_rhs_location(%d, %d)[",
376 effective_rule_length, n);
377 }
378 else
379 complain_at (at_loc, _("integer out of range: %s"), quote (text));
380 }
381 }
382
383
384 /*-------------------------.
385 | Initialize the scanner. |
386 `-------------------------*/
387
388 /* Translate the dollars and ats in \a self, in the context \a sc_context
389 (SC_RULE_ACTION, SC_SYMBOL_ACTION, INITIAL). */
390
391 static char const *
392 translate_action (code_props *self, int sc_context)
393 {
394 char *res;
395 static bool initialized = false;
396 if (!initialized)
397 {
398 obstack_init (&obstack_for_string);
399 yy_flex_debug = 0;
400 initialized = true;
401 }
402
403 loc->start = loc->end = self->location.start;
404 yy_switch_to_buffer (yy_scan_string (self->code));
405 res = code_lex (self, sc_context);
406 yy_delete_buffer (YY_CURRENT_BUFFER);
407
408 return res;
409 }
410
411 /*------------------------------------------------------------------------.
412 | Implementation of the public interface as documented in "scan-code.h". |
413 `------------------------------------------------------------------------*/
414
415 void
416 code_props_none_init (code_props *self)
417 {
418 *self = code_props_none;
419 }
420
421 code_props const code_props_none = CODE_PROPS_NONE_INIT;
422
423 void
424 code_props_plain_init (code_props *self, char const *code, location code_loc)
425 {
426 self->kind = CODE_PROPS_PLAIN;
427 self->code = code;
428 self->location = code_loc;
429 self->is_value_used = false;
430 self->rule = NULL;
431 }
432
433 void
434 code_props_symbol_action_init (code_props *self, char const *code,
435 location code_loc)
436 {
437 self->kind = CODE_PROPS_SYMBOL_ACTION;
438 self->code = code;
439 self->location = code_loc;
440 self->is_value_used = false;
441 self->rule = NULL;
442 }
443
444 void
445 code_props_rule_action_init (code_props *self, char const *code,
446 location code_loc, symbol_list *rule)
447 {
448 self->kind = CODE_PROPS_RULE_ACTION;
449 self->code = code;
450 self->location = code_loc;
451 self->is_value_used = false;
452 self->rule = rule;
453 }
454
455 void
456 code_props_translate_code (code_props *self)
457 {
458 switch (self->kind)
459 {
460 case CODE_PROPS_NONE:
461 break;
462 case CODE_PROPS_PLAIN:
463 self->code = translate_action (self, INITIAL);
464 break;
465 case CODE_PROPS_SYMBOL_ACTION:
466 self->code = translate_action (self, SC_SYMBOL_ACTION);
467 break;
468 case CODE_PROPS_RULE_ACTION:
469 self->code = translate_action (self, SC_RULE_ACTION);
470 break;
471 }
472 }
473
474 void
475 code_scanner_last_string_free (void)
476 {
477 STRING_FREE;
478 }
479
480 void
481 code_scanner_free (void)
482 {
483 obstack_free (&obstack_for_string, 0);
484 /* Reclaim Flex's buffers. */
485 yylex_destroy ();
486 }