]> git.saurik.com Git - bison.git/blame - src/scan-gram.l
Copy BYacc's nice way to report the grammar.
[bison.git] / src / scan-gram.l
CommitLineData
e9955c83
AD
1/* Bison Grammar Scanner -*- C -*-
2 Copyright (C) 2002 Free Software Foundation, Inc.
3
4 This file is part of Bison, the GNU Compiler Compiler.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA
20*/
21
22%option debug nodefault noyywrap nounput never-interactive stack
23%option prefix="gram_" outfile="lex.yy.c"
24
25%{
26#include "system.h"
27#include "complain.h"
28#include "quote.h"
29#include "getargs.h"
30#include "gram.h"
31#include "reader.h"
32
33/* Each time we match a string, move the end cursor to its end. */
8efe435c
AD
34#define YY_USER_INIT \
35do { \
36 LOCATION_RESET (*yylloc); \
37 /* This is only to avoid GCC warnings. */ \
38 if (yycontrol) {;}; \
39} while (0)
40
e9955c83
AD
41#define YY_USER_ACTION LOCATION_COLUMNS (*yylloc, yyleng)
42#define YY_LINES LOCATION_LINES (*yylloc, yyleng); lineno += yyleng;
43#define YY_STEP LOCATION_STEP (*yylloc)
44
44995b2e
AD
45
46/* STRING_OBSTACK -- Used to store all the characters that we need to
47 keep (to construct ID, STRINGS etc.). Use the following macros to
48 use it.
49
1d6412ad
AD
50 Use YY_OBS_GROW to append what has just been matched, and
51 YY_OBS_FINISH to end the string (it puts the ending 0).
52 YY_OBS_FINISH also stores this string in LAST_STRING, which can be
53 used, and which is used by YY_OBS_FREE to free the last string. */
44995b2e
AD
54
55static struct obstack string_obstack;
56char *last_string;
57
44995b2e
AD
58#define YY_OBS_GROW \
59 obstack_grow (&string_obstack, yytext, yyleng)
60
61#define YY_OBS_FINISH \
62 do { \
63 obstack_1grow (&string_obstack, '\0'); \
64 last_string = obstack_finish (&string_obstack); \
44995b2e
AD
65 } while (0)
66
67#define YY_OBS_FREE \
68 do { \
69 obstack_free (&string_obstack, last_string); \
70 } while (0)
e9955c83 71
4cdb01db
AD
72void
73scanner_last_string_free (void)
74{
75 YY_OBS_FREE;
76}
77
78
44995b2e 79
e9955c83
AD
80static int braces_level = 0;
81static int percent_percent_count = 0;
82
83static void handle_dollar PARAMS ((char *cp));
84static void handle_at PARAMS ((char *cp));
85
86%}
87%x SC_COMMENT
88%x SC_STRING SC_CHARACTER
89%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
90%x SC_BRACED_CODE SC_PROLOGUE SC_EPILOGUE
91
92id [.a-zA-Z][.a-zA-Z_0-9]*
93int [0-9]+
94eols (\n|\r|\n\r|\r\n)+
95blanks [ \t\f]+
96
97%%
98%{
99 /* At each yylex invocation, mark the current position as the
100 start of the next token. */
101#define TR_POS 0
102#if TR_POS
8efe435c 103 fprintf (stderr, "FOO1: %p: ", yylloc);
e9955c83
AD
104 LOCATION_PRINT (stderr, *yylloc);
105 fprintf (stderr, "\n");
106#endif
107 YY_STEP;
108#if TR_POS
109 fprintf (stderr, "BAR1: ");
110 LOCATION_PRINT (stderr, *yylloc);
111 fprintf (stderr, "\n");
112#endif
113%}
114
115
116 /*----------------------------.
117 | Scanning Bison directives. |
118 `----------------------------*/
119<INITIAL>
120{
121 "%binary" return PERCENT_NONASSOC;
122 "%debug" return PERCENT_DEBUG;
123 "%define" return PERCENT_DEFINE;
124 "%defines" return PERCENT_DEFINES;
125 "%error"[-_]"verbose" return PERCENT_ERROR_VERBOSE;
126 "%expect" return PERCENT_EXPECT;
127 "%file-prefix" return PERCENT_FILE_PREFIX;
128 "%fixed"[-_]"output"[-_]"files" return PERCENT_YACC;
129 "%left" return PERCENT_LEFT;
130 "%locations" return PERCENT_LOCATIONS;
131 "%name"[-_]"prefix" return PERCENT_NAME_PREFIX;
132 "%no"[-_]"lines" return PERCENT_NO_LINES;
133 "%nonassoc" return PERCENT_NONASSOC;
134 "%nterm" return PERCENT_NTERM;
135 "%output" return PERCENT_OUTPUT;
136 "%prec" return PERCENT_PREC;
137 "%pure"[-_]"parser" return PERCENT_PURE_PARSER;
138 "%right" return PERCENT_RIGHT;
139 "%skeleton" return PERCENT_SKELETON;
140 "%start" return PERCENT_START;
141 "%term" return PERCENT_TOKEN;
142 "%token" return PERCENT_TOKEN;
143 "%token"[-_]"table" return PERCENT_TOKEN_TABLE;
144 "%type" return PERCENT_TYPE;
145 "%union" return PERCENT_UNION;
146 "%verbose" return PERCENT_VERBOSE;
147 "%yacc" return PERCENT_YACC;
148
149 "=" return EQUAL;
150 ":" return COLON;
151 "|" return PIPE;
152 ";" return SEMICOLON;
153
154 {eols} YY_LINES; YY_STEP;
155 {blanks} YY_STEP;
156 {id} {
ee000ba4 157 yylval->symbol = getsym (yytext, *yylloc);
e9955c83
AD
158 return ID;
159 }
160
161 {int} yylval->integer = strtol (yytext, 0, 10); return INT;
162
163 /* Characters. We don't check there is only one. */
1d6412ad 164 \' YY_OBS_GROW; yy_push_state (SC_ESCAPED_CHARACTER);
e9955c83
AD
165
166 /* Strings. */
1d6412ad 167 \" YY_OBS_GROW; yy_push_state (SC_ESCAPED_STRING);
e9955c83
AD
168
169 /* Comments. */
170 "/*" yy_push_state (SC_COMMENT);
171 "//".* YY_STEP;
172
173 /* Prologue. */
1d6412ad 174 "%{" yy_push_state (SC_PROLOGUE);
e9955c83
AD
175
176 /* Code in between braces. */
1d6412ad 177 "{" YY_OBS_GROW; ++braces_level; yy_push_state (SC_BRACED_CODE);
e9955c83
AD
178
179 /* A type. */
4cdb01db 180 "<"[^>]+">" {
4cdb01db
AD
181 obstack_grow (&string_obstack, yytext + 1, yyleng - 2);
182 YY_OBS_FINISH;
183 yylval->string = last_string;
184 return TYPE;
185 }
186
e9955c83
AD
187
188 "%%" {
189 if (++percent_percent_count == 2)
190 yy_push_state (SC_EPILOGUE);
191 return PERCENT_PERCENT;
192 }
193
194 . {
195 LOCATION_PRINT (stderr, *yylloc);
196 fprintf (stderr, ": invalid character: `%c'\n", *yytext);
197 YY_STEP;
198 }
199}
200
201
202 /*------------------------------------------------------------.
203 | Whatever the start condition (but those which correspond to |
204 | entity `swallowed' by Bison: SC_ESCAPED_STRING and |
205 | SC_ESCAPED_CHARACTER), no M4 character must escape as is. |
206 `------------------------------------------------------------*/
207
208<SC_COMMENT,SC_STRING,SC_CHARACTER,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
209{
1d6412ad
AD
210 \[ if (YY_START != SC_COMMENT) obstack_sgrow (&string_obstack, "@<:@");
211 \] if (YY_START != SC_COMMENT) obstack_sgrow (&string_obstack, "@:>@");
e9955c83
AD
212}
213
214
215
216 /*-----------------------------------------------------------.
217 | Scanning a C comment. The initial `/ *' is already eaten. |
218 `-----------------------------------------------------------*/
219
220<SC_COMMENT>
221{
222 "*/" { /* End of the comment. */
223 if (yy_top_state () == INITIAL)
224 {
225 YY_STEP;
226 }
227 else
228 {
44995b2e 229 YY_OBS_GROW;
e9955c83
AD
230 }
231 yy_pop_state ();
232 }
233
44995b2e
AD
234 [^\[\]*\n\r]+ if (yy_top_state () != INITIAL) YY_OBS_GROW;
235 {eols} if (yy_top_state () != INITIAL) YY_OBS_GROW; YY_LINES;
236 . /* Stray `*'. */if (yy_top_state () != INITIAL) YY_OBS_GROW;
e9955c83
AD
237
238 <<EOF>> {
239 LOCATION_PRINT (stderr, *yylloc);
240 fprintf (stderr, ": unexpected end of file in a comment\n");
241 yy_pop_state ();
242 }
243}
244
245
246 /*----------------------------------------------------------------.
247 | Scanning a C string, including its escapes. The initial `"' is |
248 | already eaten. |
249 `----------------------------------------------------------------*/
250
251<SC_ESCAPED_STRING>
252{
253 \" {
254 assert (yy_top_state () == INITIAL);
44995b2e
AD
255 YY_OBS_GROW;
256 YY_OBS_FINISH;
4cdb01db 257 yylval->string = last_string;
e9955c83
AD
258 yy_pop_state ();
259 return STRING;
260 }
261
44995b2e 262 [^\"\n\r\\]+ YY_OBS_GROW;
e9955c83
AD
263
264 {eols} obstack_1grow (&string_obstack, '\n'); YY_LINES;
265
266 <<EOF>> {
267 LOCATION_PRINT (stderr, *yylloc);
268 fprintf (stderr, ": unexpected end of file in a string\n");
269 assert (yy_top_state () == INITIAL);
44995b2e 270 YY_OBS_FINISH;
4cdb01db 271 yylval->string = last_string;
e9955c83
AD
272 yy_pop_state ();
273 return STRING;
274 }
275}
276
277 /*---------------------------------------------------------------.
278 | Scanning a C character, decoding its escapes. The initial "'" |
279 | is already eaten. |
280 `---------------------------------------------------------------*/
281
282<SC_ESCAPED_CHARACTER>
283{
284 \' {
44995b2e 285 YY_OBS_GROW;
e9955c83
AD
286 assert (yy_top_state () == INITIAL);
287 {
44995b2e 288 YY_OBS_FINISH;
ee000ba4 289 yylval->symbol = getsym (last_string, *yylloc);
e9955c83 290 symbol_class_set (yylval->symbol, token_sym);
44995b2e
AD
291 symbol_user_token_number_set (yylval->symbol, last_string[1]);
292 YY_OBS_FREE;
e9955c83
AD
293 yy_pop_state ();
294 return ID;
295 }
296 }
297
44995b2e 298 [^\'\n\r\\] YY_OBS_GROW;
e9955c83
AD
299
300 {eols} obstack_1grow (&string_obstack, '\n'); YY_LINES;
301
302 <<EOF>> {
303 LOCATION_PRINT (stderr, *yylloc);
304 fprintf (stderr, ": unexpected end of file in a character\n");
305 assert (yy_top_state () == INITIAL);
44995b2e 306 YY_OBS_FINISH;
4cdb01db 307 yylval->string = last_string;
e9955c83
AD
308 yy_pop_state ();
309 return CHARACTER;
310 }
311}
312
313
314 /*----------------------------.
315 | Decode escaped characters. |
316 `----------------------------*/
317
318<SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
319{
320 \\[0-7]{3} {
321 long c = strtol (yytext + 1, 0, 8);
322 if (c > 255)
323 {
324 LOCATION_PRINT (stderr, *yylloc);
325 fprintf (stderr, ": invalid escape: %s\n", yytext);
326 YY_STEP;
327 }
328 else
329 obstack_1grow (&string_obstack, c);
330 }
331
332 \\x[0-9a-fA-F]{2} {
333 obstack_1grow (&string_obstack, strtol (yytext + 2, 0, 16));
334 }
335
336 \\a obstack_1grow (&string_obstack, '\a');
337 \\b obstack_1grow (&string_obstack, '\b');
338 \\f obstack_1grow (&string_obstack, '\f');
339 \\n obstack_1grow (&string_obstack, '\n');
340 \\r obstack_1grow (&string_obstack, '\r');
341 \\t obstack_1grow (&string_obstack, '\t');
342 \\v obstack_1grow (&string_obstack, '\v');
343 \\[\\""] obstack_1grow (&string_obstack, yytext[1]);
344 \\. {
345 LOCATION_PRINT (stderr, *yylloc);
346 fprintf (stderr, ": unrecognized escape: %s\n", yytext);
44995b2e 347 YY_OBS_GROW;
e9955c83
AD
348 }
349}
350
351
352 /*----------------------------------------------------------.
353 | Scanning a C character without decoding its escapes. The |
354 | initial "'" is already eaten. |
355 `----------------------------------------------------------*/
356
357<SC_CHARACTER>
358{
359 \' {
44995b2e 360 YY_OBS_GROW;
e9955c83
AD
361 assert (yy_top_state () != INITIAL);
362 yy_pop_state ();
363 }
364
44995b2e
AD
365 [^\[\]\'\n\r\\] YY_OBS_GROW;
366 \\. YY_OBS_GROW;
e9955c83 367
44995b2e 368 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
369
370 <<EOF>> {
371 LOCATION_PRINT (stderr, *yylloc);
372 fprintf (stderr, ": unexpected end of file in a character\n");
373 assert (yy_top_state () != INITIAL);
374 yy_pop_state ();
375 }
376}
377
378
379 /*----------------------------------------------------------------.
380 | Scanning a C string, without decoding its escapes. The initial |
381 | `"' is already eaten. |
382 `----------------------------------------------------------------*/
383
384<SC_STRING>
385{
386 \" {
387 assert (yy_top_state () != INITIAL);
44995b2e 388 YY_OBS_GROW;
e9955c83
AD
389 yy_pop_state ();
390 }
391
44995b2e
AD
392 [^\[\]\"\n\r\\]+ YY_OBS_GROW;
393 \\. YY_OBS_GROW;
e9955c83 394
44995b2e 395 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
396
397 <<EOF>> {
398 LOCATION_PRINT (stderr, *yylloc);
399 fprintf (stderr, ": unexpected end of file in a string\n");
400 assert (yy_top_state () != INITIAL);
401 yy_pop_state ();
402 }
403}
404
405
406 /*---------------------------------------------------.
407 | Strings, comments etc. can be found in user code. |
408 `---------------------------------------------------*/
409
410<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
411{
412 /* Characters. We don't check there is only one. */
44995b2e 413 \' YY_OBS_GROW; yy_push_state (SC_CHARACTER);
e9955c83
AD
414
415 /* Strings. */
44995b2e 416 \" YY_OBS_GROW; yy_push_state (SC_STRING);
e9955c83
AD
417
418 /* Comments. */
44995b2e
AD
419 "/*" YY_OBS_GROW; yy_push_state (SC_COMMENT);
420 "//".* YY_OBS_GROW;
e9955c83
AD
421}
422
423
424 /*---------------------------------------------------------------.
425 | Scanning some code in braces (%union and actions). The initial |
426 | "{" is already eaten. |
427 `---------------------------------------------------------------*/
428
429<SC_BRACED_CODE>
430{
431 "}" {
44995b2e 432 YY_OBS_GROW;
e9955c83
AD
433 if (--braces_level == 0)
434 {
435 yy_pop_state ();
44995b2e 436 YY_OBS_FINISH;
4cdb01db 437 yylval->string = last_string;
e9955c83
AD
438 return BRACED_CODE;
439 }
440 }
441
44995b2e 442 "{" YY_OBS_GROW; braces_level++;
e9955c83 443
75d1fe16 444 "$"("<"[^>]+">")?(-?[0-9]+|"$") { handle_dollar (yytext); }
e9955c83
AD
445 "@"(-?[0-9]+|"$") { handle_at (yytext); }
446
6c35d22c 447 [^$@\[\]/\'\"\{\}\n\r]+ YY_OBS_GROW;
44995b2e 448 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
449
450 /* A lose $, or /, or etc. */
44995b2e 451 . YY_OBS_GROW;
e9955c83
AD
452
453 <<EOF>> {
454 LOCATION_PRINT (stderr, *yylloc);
455 fprintf (stderr, ": unexpected end of file in a braced code\n");
456 yy_pop_state ();
44995b2e 457 YY_OBS_FINISH;
4cdb01db
AD
458 yylval->string = last_string;
459 return BRACED_CODE;
e9955c83
AD
460 }
461
462}
463
464
465 /*--------------------------------------------------------------.
466 | Scanning some prologue: from "%{" (already scanned) to "%}". |
467 `--------------------------------------------------------------*/
468
469<SC_PROLOGUE>
470{
471 "%}" {
472 yy_pop_state ();
44995b2e 473 YY_OBS_FINISH;
4cdb01db 474 yylval->string = last_string;
e9955c83
AD
475 return PROLOGUE;
476 }
477
6c35d22c 478 [^%\[\]/\'\"\n\r]+ YY_OBS_GROW;
44995b2e
AD
479 "%"+[^%\}\n\r]+ YY_OBS_GROW;
480 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
481
482 <<EOF>> {
483 LOCATION_PRINT (stderr, *yylloc);
484 fprintf (stderr, ": unexpected end of file in a prologue\n");
485 yy_pop_state ();
44995b2e 486 YY_OBS_FINISH;
4cdb01db 487 yylval->string = last_string;
e9955c83
AD
488 return PROLOGUE;
489 }
490
491}
492
493
494 /*---------------------------------------------------------------.
495 | Scanning the epilogue (everything after the second "%%", which |
496 | has already been eaten. |
497 `---------------------------------------------------------------*/
498
499<SC_EPILOGUE>
500{
44995b2e 501 ([^\[\]]|{eols})+ YY_OBS_GROW;
e9955c83
AD
502
503 <<EOF>> {
504 yy_pop_state ();
44995b2e 505 YY_OBS_FINISH;
4cdb01db 506 yylval->string = last_string;
e9955c83
AD
507 return EPILOGUE;
508 }
509}
510
511
512%%
513
514/*------------------------------------------------------------------.
515| CP is pointing to a wannabee semantic value (i.e., a `$'). |
516| |
517| Possible inputs: $[<TYPENAME>]($|integer) |
518| |
519| Output to the STRING_OBSTACK a reference to this semantic value. |
520`------------------------------------------------------------------*/
521
522static void
523handle_dollar (char *cp)
524{
525 const char *type_name = NULL;
526
527 /* RULE_LENGTH is the number of values in the current rule so far,
528 which says where to find `$0' with respect to the top of the
529 stack. It is not the same as the rule->length in the case of mid
530 rule actions. */
531 int rule_length = 0;
532 symbol_list *rhs;
533 for (rhs = current_rule->next; rhs; rhs = rhs->next)
534 ++rule_length;
535
536 ++cp;
537
538 /* Get the type name if explicit. */
539 if (*cp == '<')
540 {
541 type_name = ++cp;
542 while (*cp != '>')
543 ++cp;
544 *cp = '\0';
545 ++cp;
546 }
547
548 if (*cp == '$')
549 {
550 if (!type_name)
551 type_name = get_type_name (0, current_rule);
552 if (!type_name && typed)
553 complain (_("$$ of `%s' has no declared type"),
554 current_rule->sym->tag);
555 if (!type_name)
556 type_name = "";
557 obstack_fgrow1 (&string_obstack,
558 "]b4_lhs_value([%s])[", type_name);
559 }
560 else if (isdigit (*cp) || *cp == '-')
561 {
562 int n = strtol (cp, &cp, 10);
563
564 if (n > rule_length)
565 complain (_("invalid value: %s%d"), "$", n);
566 else
567 {
568 if (!type_name && n > 0)
569 type_name = get_type_name (n, current_rule);
570 if (!type_name && typed)
571 complain (_("$%d of `%s' has no declared type"),
572 n, current_rule->sym->tag);
573 if (!type_name)
574 type_name = "";
575 obstack_fgrow3 (&string_obstack,
576 "]b4_rhs_value([%d], [%d], [%s])[",
577 rule_length, n, type_name);
578 }
579 }
580 else
581 {
582 char buf[] = "$c";
583 buf[1] = *cp;
584 complain (_("%s is invalid"), quote (buf));
585 }
586}
587
588/*-------------------------------------------------------.
589| CP is pointing to a location (i.e., a `@'). Output to |
590| STRING_OBSTACK a reference to this location. |
591`-------------------------------------------------------*/
592
593static void
594handle_at (char *cp)
595{
596 /* RULE_LENGTH is the number of values in the current rule so far,
597 which says where to find `$0' with respect to the top of the
598 stack. It is not the same as the rule->length in the case of mid
599 rule actions. */
600 int rule_length = 0;
601 symbol_list *rhs;
602 for (rhs = current_rule->next; rhs; rhs = rhs->next)
603 ++rule_length;
604
605 locations_flag = 1;
606 ++cp;
607
608 if (*cp == '$')
609 {
610 obstack_sgrow (&string_obstack, "]b4_lhs_location[");
611 }
612 else if (isdigit (*cp) || *cp == '-')
613 {
614 int n = strtol (cp, &cp, 10);
615 if (n > rule_length)
616 complain (_("invalid value: %s%d"), "@", n);
617 else
618 obstack_fgrow2 (&string_obstack, "]b4_rhs_location([%d], [%d])[",
619 rule_length, n);
620 }
621 else
622 {
623 char buf[] = "@c";
624 buf[1] = *cp;
625 complain (_("%s is invalid"), quote (buf));
626 }
627}
4cdb01db 628
1d6412ad
AD
629void
630scanner_initialize (void)
631{
632 obstack_init (&string_obstack);
633}
634
635
4cdb01db
AD
636void
637scanner_free (void)
638{
639 obstack_free (&string_obstack, 0);
640}