]> git.saurik.com Git - bison.git/blame - src/scan-gram.l
We spend a lot of time in quotearg, in particular when --verbose.
[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
e9955c83
AD
79static int braces_level = 0;
80static int percent_percent_count = 0;
81
f25bfb75
AD
82static void handle_dollar PARAMS ((braced_code_t code_kind,
83 char *cp, location_t location));
84static void handle_at PARAMS ((braced_code_t code_kind,
85 char *cp, location_t location));
e9955c83
AD
86
87%}
88%x SC_COMMENT
89%x SC_STRING SC_CHARACTER
90%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
91%x SC_BRACED_CODE SC_PROLOGUE SC_EPILOGUE
92
93id [.a-zA-Z][.a-zA-Z_0-9]*
94int [0-9]+
95eols (\n|\r|\n\r|\r\n)+
96blanks [ \t\f]+
97
98%%
99%{
100 /* At each yylex invocation, mark the current position as the
101 start of the next token. */
102#define TR_POS 0
103#if TR_POS
8efe435c 104 fprintf (stderr, "FOO1: %p: ", yylloc);
e9955c83
AD
105 LOCATION_PRINT (stderr, *yylloc);
106 fprintf (stderr, "\n");
107#endif
108 YY_STEP;
109#if TR_POS
110 fprintf (stderr, "BAR1: ");
111 LOCATION_PRINT (stderr, *yylloc);
112 fprintf (stderr, "\n");
113#endif
114%}
115
116
117 /*----------------------------.
118 | Scanning Bison directives. |
119 `----------------------------*/
120<INITIAL>
121{
122 "%binary" return PERCENT_NONASSOC;
123 "%debug" return PERCENT_DEBUG;
124 "%define" return PERCENT_DEFINE;
125 "%defines" return PERCENT_DEFINES;
9280d3ef 126 "%destructor" return PERCENT_DESTRUCTOR;
676385e2 127 "%dprec" return PERCENT_DPREC;
e9955c83
AD
128 "%error"[-_]"verbose" return PERCENT_ERROR_VERBOSE;
129 "%expect" return PERCENT_EXPECT;
130 "%file-prefix" return PERCENT_FILE_PREFIX;
131 "%fixed"[-_]"output"[-_]"files" return PERCENT_YACC;
676385e2 132 "%glr"[-_]"parser" return PERCENT_GLR_PARSER;
e9955c83
AD
133 "%left" return PERCENT_LEFT;
134 "%locations" return PERCENT_LOCATIONS;
676385e2 135 "%merge" return PERCENT_MERGE;
e9955c83
AD
136 "%name"[-_]"prefix" return PERCENT_NAME_PREFIX;
137 "%no"[-_]"lines" return PERCENT_NO_LINES;
138 "%nonassoc" return PERCENT_NONASSOC;
139 "%nterm" return PERCENT_NTERM;
140 "%output" return PERCENT_OUTPUT;
141 "%prec" return PERCENT_PREC;
366eea36 142 "%printer" return PERCENT_PRINTER;
e9955c83
AD
143 "%pure"[-_]"parser" return PERCENT_PURE_PARSER;
144 "%right" return PERCENT_RIGHT;
145 "%skeleton" return PERCENT_SKELETON;
146 "%start" return PERCENT_START;
147 "%term" return PERCENT_TOKEN;
148 "%token" return PERCENT_TOKEN;
149 "%token"[-_]"table" return PERCENT_TOKEN_TABLE;
150 "%type" return PERCENT_TYPE;
151 "%union" return PERCENT_UNION;
152 "%verbose" return PERCENT_VERBOSE;
153 "%yacc" return PERCENT_YACC;
154
155 "=" return EQUAL;
156 ":" return COLON;
157 "|" return PIPE;
158 ";" return SEMICOLON;
159
160 {eols} YY_LINES; YY_STEP;
161 {blanks} YY_STEP;
162 {id} {
39f41916 163 yylval->symbol = symbol_get (yytext, *yylloc);
e9955c83
AD
164 return ID;
165 }
166
167 {int} yylval->integer = strtol (yytext, 0, 10); return INT;
168
169 /* Characters. We don't check there is only one. */
1d6412ad 170 \' YY_OBS_GROW; yy_push_state (SC_ESCAPED_CHARACTER);
e9955c83
AD
171
172 /* Strings. */
1d6412ad 173 \" YY_OBS_GROW; yy_push_state (SC_ESCAPED_STRING);
e9955c83
AD
174
175 /* Comments. */
176 "/*" yy_push_state (SC_COMMENT);
177 "//".* YY_STEP;
178
179 /* Prologue. */
1d6412ad 180 "%{" yy_push_state (SC_PROLOGUE);
e9955c83
AD
181
182 /* Code in between braces. */
1d6412ad 183 "{" YY_OBS_GROW; ++braces_level; yy_push_state (SC_BRACED_CODE);
e9955c83
AD
184
185 /* A type. */
4cdb01db 186 "<"[^>]+">" {
4cdb01db
AD
187 obstack_grow (&string_obstack, yytext + 1, yyleng - 2);
188 YY_OBS_FINISH;
189 yylval->string = last_string;
190 return TYPE;
191 }
192
e9955c83
AD
193
194 "%%" {
195 if (++percent_percent_count == 2)
196 yy_push_state (SC_EPILOGUE);
197 return PERCENT_PERCENT;
198 }
199
200 . {
201 LOCATION_PRINT (stderr, *yylloc);
202 fprintf (stderr, ": invalid character: `%c'\n", *yytext);
203 YY_STEP;
204 }
205}
206
207
208 /*------------------------------------------------------------.
209 | Whatever the start condition (but those which correspond to |
210 | entity `swallowed' by Bison: SC_ESCAPED_STRING and |
211 | SC_ESCAPED_CHARACTER), no M4 character must escape as is. |
212 `------------------------------------------------------------*/
213
214<SC_COMMENT,SC_STRING,SC_CHARACTER,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
215{
1d6412ad
AD
216 \[ if (YY_START != SC_COMMENT) obstack_sgrow (&string_obstack, "@<:@");
217 \] if (YY_START != SC_COMMENT) obstack_sgrow (&string_obstack, "@:>@");
e9955c83
AD
218}
219
220
221
222 /*-----------------------------------------------------------.
223 | Scanning a C comment. The initial `/ *' is already eaten. |
224 `-----------------------------------------------------------*/
225
226<SC_COMMENT>
227{
228 "*/" { /* End of the comment. */
229 if (yy_top_state () == INITIAL)
230 {
231 YY_STEP;
232 }
233 else
234 {
44995b2e 235 YY_OBS_GROW;
e9955c83
AD
236 }
237 yy_pop_state ();
238 }
239
44995b2e
AD
240 [^\[\]*\n\r]+ if (yy_top_state () != INITIAL) YY_OBS_GROW;
241 {eols} if (yy_top_state () != INITIAL) YY_OBS_GROW; YY_LINES;
242 . /* Stray `*'. */if (yy_top_state () != INITIAL) YY_OBS_GROW;
e9955c83
AD
243
244 <<EOF>> {
245 LOCATION_PRINT (stderr, *yylloc);
246 fprintf (stderr, ": unexpected end of file in a comment\n");
247 yy_pop_state ();
248 }
249}
250
251
252 /*----------------------------------------------------------------.
253 | Scanning a C string, including its escapes. The initial `"' is |
254 | already eaten. |
255 `----------------------------------------------------------------*/
256
257<SC_ESCAPED_STRING>
258{
259 \" {
260 assert (yy_top_state () == INITIAL);
44995b2e
AD
261 YY_OBS_GROW;
262 YY_OBS_FINISH;
4cdb01db 263 yylval->string = last_string;
e9955c83
AD
264 yy_pop_state ();
265 return STRING;
266 }
267
44995b2e 268 [^\"\n\r\\]+ YY_OBS_GROW;
e9955c83
AD
269
270 {eols} obstack_1grow (&string_obstack, '\n'); YY_LINES;
271
272 <<EOF>> {
273 LOCATION_PRINT (stderr, *yylloc);
274 fprintf (stderr, ": unexpected end of file in a string\n");
275 assert (yy_top_state () == INITIAL);
44995b2e 276 YY_OBS_FINISH;
4cdb01db 277 yylval->string = last_string;
e9955c83
AD
278 yy_pop_state ();
279 return STRING;
280 }
281}
282
283 /*---------------------------------------------------------------.
284 | Scanning a C character, decoding its escapes. The initial "'" |
285 | is already eaten. |
286 `---------------------------------------------------------------*/
287
288<SC_ESCAPED_CHARACTER>
289{
290 \' {
44995b2e 291 YY_OBS_GROW;
e9955c83
AD
292 assert (yy_top_state () == INITIAL);
293 {
44995b2e 294 YY_OBS_FINISH;
39f41916 295 yylval->symbol = symbol_get (last_string, *yylloc);
e776192e
AD
296 symbol_class_set (yylval->symbol, token_sym, *yylloc);
297 symbol_user_token_number_set (yylval->symbol, last_string[1], *yylloc);
44995b2e 298 YY_OBS_FREE;
e9955c83
AD
299 yy_pop_state ();
300 return ID;
301 }
302 }
303
44995b2e 304 [^\'\n\r\\] YY_OBS_GROW;
e9955c83
AD
305
306 {eols} obstack_1grow (&string_obstack, '\n'); YY_LINES;
307
308 <<EOF>> {
309 LOCATION_PRINT (stderr, *yylloc);
310 fprintf (stderr, ": unexpected end of file in a character\n");
311 assert (yy_top_state () == INITIAL);
44995b2e 312 YY_OBS_FINISH;
4cdb01db 313 yylval->string = last_string;
e9955c83
AD
314 yy_pop_state ();
315 return CHARACTER;
316 }
317}
318
319
320 /*----------------------------.
321 | Decode escaped characters. |
322 `----------------------------*/
323
324<SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
325{
326 \\[0-7]{3} {
327 long c = strtol (yytext + 1, 0, 8);
328 if (c > 255)
329 {
330 LOCATION_PRINT (stderr, *yylloc);
4f25ebb0 331 fprintf (stderr, ": invalid escape: %s\n", quote (yytext));
e9955c83
AD
332 YY_STEP;
333 }
334 else
335 obstack_1grow (&string_obstack, c);
336 }
337
338 \\x[0-9a-fA-F]{2} {
339 obstack_1grow (&string_obstack, strtol (yytext + 2, 0, 16));
340 }
341
342 \\a obstack_1grow (&string_obstack, '\a');
343 \\b obstack_1grow (&string_obstack, '\b');
344 \\f obstack_1grow (&string_obstack, '\f');
345 \\n obstack_1grow (&string_obstack, '\n');
346 \\r obstack_1grow (&string_obstack, '\r');
347 \\t obstack_1grow (&string_obstack, '\t');
348 \\v obstack_1grow (&string_obstack, '\v');
349 \\[\\""] obstack_1grow (&string_obstack, yytext[1]);
4f25ebb0 350 \\(.|\n) {
e9955c83 351 LOCATION_PRINT (stderr, *yylloc);
4f25ebb0 352 fprintf (stderr, ": unrecognized escape: %s\n", quote (yytext));
44995b2e 353 YY_OBS_GROW;
e9955c83 354 }
4f25ebb0
AD
355 /* FLex wants this rule, in case of a `\<<EOF>>'. */
356 \\ YY_OBS_GROW;
e9955c83
AD
357}
358
359
360 /*----------------------------------------------------------.
361 | Scanning a C character without decoding its escapes. The |
362 | initial "'" is already eaten. |
363 `----------------------------------------------------------*/
364
365<SC_CHARACTER>
366{
367 \' {
44995b2e 368 YY_OBS_GROW;
e9955c83
AD
369 assert (yy_top_state () != INITIAL);
370 yy_pop_state ();
371 }
372
4f25ebb0
AD
373 [^\[\]\'\n\r\\]+ YY_OBS_GROW;
374 \\(.|\n) YY_OBS_GROW;
375 /* FLex wants this rule, in case of a `\<<EOF>>'. */
376 \\ YY_OBS_GROW;
e9955c83 377
44995b2e 378 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
379
380 <<EOF>> {
381 LOCATION_PRINT (stderr, *yylloc);
382 fprintf (stderr, ": unexpected end of file in a character\n");
383 assert (yy_top_state () != INITIAL);
384 yy_pop_state ();
385 }
386}
387
388
389 /*----------------------------------------------------------------.
390 | Scanning a C string, without decoding its escapes. The initial |
391 | `"' is already eaten. |
392 `----------------------------------------------------------------*/
393
394<SC_STRING>
395{
396 \" {
397 assert (yy_top_state () != INITIAL);
44995b2e 398 YY_OBS_GROW;
e9955c83
AD
399 yy_pop_state ();
400 }
401
44995b2e 402 [^\[\]\"\n\r\\]+ YY_OBS_GROW;
4f25ebb0
AD
403 \\(.|\n) YY_OBS_GROW;
404 /* FLex wants this rule, in case of a `\<<EOF>>'. */
405 \\ YY_OBS_GROW;
e9955c83 406
44995b2e 407 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
408
409 <<EOF>> {
410 LOCATION_PRINT (stderr, *yylloc);
411 fprintf (stderr, ": unexpected end of file in a string\n");
412 assert (yy_top_state () != INITIAL);
413 yy_pop_state ();
414 }
415}
416
417
418 /*---------------------------------------------------.
419 | Strings, comments etc. can be found in user code. |
420 `---------------------------------------------------*/
421
422<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
423{
424 /* Characters. We don't check there is only one. */
44995b2e 425 \' YY_OBS_GROW; yy_push_state (SC_CHARACTER);
e9955c83
AD
426
427 /* Strings. */
44995b2e 428 \" YY_OBS_GROW; yy_push_state (SC_STRING);
e9955c83
AD
429
430 /* Comments. */
44995b2e
AD
431 "/*" YY_OBS_GROW; yy_push_state (SC_COMMENT);
432 "//".* YY_OBS_GROW;
4f25ebb0
AD
433
434 /* Not comments. */
435 "/" YY_OBS_GROW;
e9955c83
AD
436}
437
438
439 /*---------------------------------------------------------------.
440 | Scanning some code in braces (%union and actions). The initial |
441 | "{" is already eaten. |
442 `---------------------------------------------------------------*/
443
444<SC_BRACED_CODE>
445{
446 "}" {
44995b2e 447 YY_OBS_GROW;
e9955c83
AD
448 if (--braces_level == 0)
449 {
450 yy_pop_state ();
44995b2e 451 YY_OBS_FINISH;
4cdb01db 452 yylval->string = last_string;
e9955c83
AD
453 return BRACED_CODE;
454 }
455 }
456
44995b2e 457 "{" YY_OBS_GROW; braces_level++;
e9955c83 458
f25bfb75
AD
459 "$"("<"[^>]+">")?(-?[0-9]+|"$") { handle_dollar (current_braced_code,
460 yytext, *yylloc); }
461 "@"(-?[0-9]+|"$") { handle_at (current_braced_code,
462 yytext, *yylloc); }
e9955c83 463
6c35d22c 464 [^$@\[\]/\'\"\{\}\n\r]+ YY_OBS_GROW;
44995b2e 465 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
466
467 /* A lose $, or /, or etc. */
44995b2e 468 . YY_OBS_GROW;
e9955c83
AD
469
470 <<EOF>> {
471 LOCATION_PRINT (stderr, *yylloc);
472 fprintf (stderr, ": unexpected end of file in a braced code\n");
473 yy_pop_state ();
44995b2e 474 YY_OBS_FINISH;
4cdb01db
AD
475 yylval->string = last_string;
476 return BRACED_CODE;
e9955c83
AD
477 }
478
479}
480
481
482 /*--------------------------------------------------------------.
483 | Scanning some prologue: from "%{" (already scanned) to "%}". |
484 `--------------------------------------------------------------*/
485
486<SC_PROLOGUE>
487{
488 "%}" {
489 yy_pop_state ();
44995b2e 490 YY_OBS_FINISH;
4cdb01db 491 yylval->string = last_string;
e9955c83
AD
492 return PROLOGUE;
493 }
494
4f25ebb0
AD
495 [^%\[\]/\'\"\n\r]+ YY_OBS_GROW;
496 "%" YY_OBS_GROW;
497 {eols} YY_OBS_GROW; YY_LINES;
e9955c83
AD
498
499 <<EOF>> {
500 LOCATION_PRINT (stderr, *yylloc);
501 fprintf (stderr, ": unexpected end of file in a prologue\n");
502 yy_pop_state ();
44995b2e 503 YY_OBS_FINISH;
4cdb01db 504 yylval->string = last_string;
e9955c83
AD
505 return PROLOGUE;
506 }
e9955c83
AD
507}
508
509
510 /*---------------------------------------------------------------.
511 | Scanning the epilogue (everything after the second "%%", which |
512 | has already been eaten. |
513 `---------------------------------------------------------------*/
514
515<SC_EPILOGUE>
516{
44995b2e 517 ([^\[\]]|{eols})+ YY_OBS_GROW;
e9955c83
AD
518
519 <<EOF>> {
520 yy_pop_state ();
44995b2e 521 YY_OBS_FINISH;
4cdb01db 522 yylval->string = last_string;
e9955c83
AD
523 return EPILOGUE;
524 }
525}
526
527
528%%
529
530/*------------------------------------------------------------------.
366eea36 531| TEXT is pointing to a wannabee semantic value (i.e., a `$'). |
e9955c83
AD
532| |
533| Possible inputs: $[<TYPENAME>]($|integer) |
534| |
535| Output to the STRING_OBSTACK a reference to this semantic value. |
536`------------------------------------------------------------------*/
537
f25bfb75 538static inline void
366eea36 539handle_action_dollar (char *text, location_t location)
e9955c83
AD
540{
541 const char *type_name = NULL;
366eea36 542 char *cp = text + 1;
e9955c83
AD
543
544 /* Get the type name if explicit. */
545 if (*cp == '<')
546 {
547 type_name = ++cp;
548 while (*cp != '>')
549 ++cp;
550 *cp = '\0';
551 ++cp;
552 }
553
554 if (*cp == '$')
555 {
556 if (!type_name)
56c47203 557 type_name = symbol_list_n_type_name_get (current_rule, location, 0);
e9955c83 558 if (!type_name && typed)
56c47203 559 complain_at (location, _("$$ of `%s' has no declared type"),
97650f4e 560 current_rule->sym->tag);
e9955c83
AD
561 if (!type_name)
562 type_name = "";
563 obstack_fgrow1 (&string_obstack,
564 "]b4_lhs_value([%s])[", type_name);
565 }
566 else if (isdigit (*cp) || *cp == '-')
567 {
dafdc66f
AD
568 /* RULE_LENGTH is the number of values in the current rule so
569 far, which says where to find `$0' with respect to the top of
570 the stack. It is not the same as the rule->length in the
571 case of mid rule actions. */
572 int rule_length = symbol_list_length (current_rule->next);
e9955c83
AD
573 int n = strtol (cp, &cp, 10);
574
575 if (n > rule_length)
56c47203 576 complain_at (location, _("invalid value: %s%d"), "$", n);
e9955c83
AD
577 else
578 {
579 if (!type_name && n > 0)
56c47203
AD
580 type_name = symbol_list_n_type_name_get (current_rule, location,
581 n);
e9955c83 582 if (!type_name && typed)
56c47203 583 complain_at (location, _("$%d of `%s' has no declared type"),
97650f4e 584 n, current_rule->sym->tag);
e9955c83
AD
585 if (!type_name)
586 type_name = "";
587 obstack_fgrow3 (&string_obstack,
588 "]b4_rhs_value([%d], [%d], [%s])[",
589 rule_length, n, type_name);
590 }
591 }
592 else
593 {
366eea36 594 complain_at (location, _("%s is invalid"), quote (text));
9280d3ef
AD
595 }
596}
597
598
366eea36
AD
599/*---------------------------------------------------------------.
600| TEXT is expexted tp be $$ in some code associated to a symbol: |
601| destructor or printer. |
602`---------------------------------------------------------------*/
9280d3ef 603
f25bfb75 604static inline void
366eea36 605handle_symbol_code_dollar (char *text, location_t location)
9280d3ef 606{
366eea36 607 char *cp = text + 1;
9280d3ef 608 if (*cp == '$')
366eea36 609 obstack_sgrow (&string_obstack, "]b4_dollar_dollar[");
9280d3ef 610 else
366eea36 611 complain_at (location, _("%s is invalid"), quote (text));
e9955c83
AD
612}
613
f25bfb75
AD
614
615/*-----------------------------------------------------------------.
616| Dispatch onto handle_action_dollar, or handle_destructor_dollar, |
617| depending upon CODE_KIND. |
618`-----------------------------------------------------------------*/
e9955c83
AD
619
620static void
f25bfb75
AD
621handle_dollar (braced_code_t braced_code_kind,
622 char *text, location_t location)
623{
624 switch (braced_code_kind)
625 {
626 case action_braced_code:
627 handle_action_dollar (text, location);
628 break;
629
630 case destructor_braced_code:
366eea36
AD
631 case printer_braced_code:
632 handle_symbol_code_dollar (text, location);
f25bfb75
AD
633 break;
634 }
635}
636
637
638/*------------------------------------------------------.
639| TEXT is a location token (i.e., a `@...'). Output to |
640| STRING_OBSTACK a reference to this location. |
641`------------------------------------------------------*/
642
643static inline void
644handle_action_at (char *text, location_t location)
e9955c83 645{
366eea36 646 char *cp = text + 1;
e9955c83 647 locations_flag = 1;
e9955c83 648
366eea36 649 if (*cp == '$')
e9955c83
AD
650 {
651 obstack_sgrow (&string_obstack, "]b4_lhs_location[");
652 }
366eea36 653 else if (isdigit (*cp) || *cp == '-')
e9955c83 654 {
dafdc66f
AD
655 /* RULE_LENGTH is the number of values in the current rule so
656 far, which says where to find `$0' with respect to the top of
657 the stack. It is not the same as the rule->length in the
658 case of mid rule actions. */
659 int rule_length = symbol_list_length (current_rule->next);
366eea36 660 int n = strtol (cp, &cp, 10);
dafdc66f 661
e9955c83 662 if (n > rule_length)
f25bfb75 663 complain_at (location, _("invalid value: %s%d"), "@", n);
e9955c83
AD
664 else
665 obstack_fgrow2 (&string_obstack, "]b4_rhs_location([%d], [%d])[",
666 rule_length, n);
667 }
668 else
669 {
366eea36 670 complain_at (location, _("%s is invalid"), quote (text));
f25bfb75
AD
671 }
672}
673
674
366eea36
AD
675/*---------------------------------------------------------------.
676| TEXT is expexted tp be @$ in some code associated to a symbol: |
677| destructor or printer. |
678`---------------------------------------------------------------*/
f25bfb75
AD
679
680static inline void
366eea36 681handle_symbol_code_at (char *text, location_t location)
f25bfb75 682{
366eea36
AD
683 char *cp = text + 1;
684 if (*cp == '$')
685 obstack_sgrow (&string_obstack, "]b4_at_dollar[");
f25bfb75 686 else
366eea36 687 complain_at (location, _("%s is invalid"), quote (text));
e9955c83 688}
4cdb01db 689
f25bfb75
AD
690
691/*-------------------------------------------------------------------.
692| Dispatch onto handle_action_at, or handle_destructor_at, depending |
693| upon CODE_KIND. |
694`-------------------------------------------------------------------*/
695
696static void
697handle_at (braced_code_t braced_code_kind,
698 char *text, location_t location)
699{
700 switch (braced_code_kind)
701 {
702 case action_braced_code:
703 handle_action_at (text, location);
704 break;
705
706 case destructor_braced_code:
366eea36
AD
707 case printer_braced_code:
708 handle_symbol_code_at (text, location);
f25bfb75
AD
709 break;
710 }
711}
712
713
714/*-------------------------.
715| Initialize the scanner. |
716`-------------------------*/
717
1d6412ad
AD
718void
719scanner_initialize (void)
720{
721 obstack_init (&string_obstack);
722}
723
724
f25bfb75
AD
725/*-----------------------------------------------.
726| Free all the memory allocated to the scanner. |
727`-----------------------------------------------*/
728
4cdb01db
AD
729void
730scanner_free (void)
731{
732 obstack_free (&string_obstack, 0);
733}