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