]> git.saurik.com Git - bison.git/blame - src/scan-gram.l
* src/location.h (LOCATION_PRINT): Use quotearg slot 3 to avoid
[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"
d8d3f94a 27#include "mbswidth.h"
e9955c83
AD
28#include "complain.h"
29#include "quote.h"
30#include "getargs.h"
31#include "gram.h"
32#include "reader.h"
33
34/* Each time we match a string, move the end cursor to its end. */
8efe435c
AD
35#define YY_USER_INIT \
36do { \
37 LOCATION_RESET (*yylloc); \
1a715ef2 38 yylloc->file = infile; \
8efe435c
AD
39 /* This is only to avoid GCC warnings. */ \
40 if (yycontrol) {;}; \
41} while (0)
42
d8d3f94a
PE
43#define YY_USER_ACTION extend_location (yylloc, yytext, yyleng);
44#define YY_STEP LOCATION_STEP (*yylloc)
45
46#define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
47
48
49/* Read bytes from FP into buffer BUF of size SIZE. Return the
50 number of bytes read. Remove '\r' from input, treating \r\n
51 and isolated \r as \n. */
52
53static size_t
54no_cr_read (FILE *fp, char *buf, size_t size)
55{
56 size_t s = fread (buf, 1, size, fp);
57 if (s)
58 {
59 char *w = memchr (buf, '\r', s);
60 if (w)
61 {
62 char const *r = ++w;
63 char const *lim = buf + s;
64
65 for (;;)
66 {
67 /* Found an '\r'. Treat it like '\n', but ignore any
68 '\n' that immediately follows. */
69 w[-1] = '\n';
70 if (r == lim)
71 {
72 int ch = getc (fp);
73 if (ch != '\n' && ungetc (ch, fp) != ch)
74 break;
75 }
76 else if (*r == '\n')
77 r++;
78
79 /* Copy until the next '\r'. */
80 do
81 {
82 if (r == lim)
83 return w - buf;
84 }
85 while ((*w++ = *r++) != '\r');
86 }
87
88 return w - buf;
89 }
90 }
91
92 return s;
93}
94
95
96/* Extend *LOC to account for token TOKEN of size SIZE. */
97
98static void
99extend_location (location_t *loc, char const *token, int size)
100{
101 int line = loc->last_line;
102 int column = loc->last_column;
103 char const *p0 = token;
104 char const *p = token;
105 char const *lim = token + size;
106
107 for (p = token; p < lim; p++)
108 switch (*p)
109 {
110 case '\r':
111 /* \r shouldn't survive no_cr_read. */
112 abort ();
113
114 case '\n':
115 line++;
116 column = 1;
117 p0 = p + 1;
118 break;
119
120 case '\t':
121 column += mbsnwidth (p0, p - p0, 0);
122 column += 8 - ((column - 1) & 7);
123 p0 = p + 1;
124 break;
125 }
126
127 loc->last_line = line;
128 loc->last_column = column + mbsnwidth (p0, p - p0, 0);
129}
130
131
e9955c83 132
44995b2e
AD
133/* STRING_OBSTACK -- Used to store all the characters that we need to
134 keep (to construct ID, STRINGS etc.). Use the following macros to
135 use it.
136
1d6412ad
AD
137 Use YY_OBS_GROW to append what has just been matched, and
138 YY_OBS_FINISH to end the string (it puts the ending 0).
139 YY_OBS_FINISH also stores this string in LAST_STRING, which can be
140 used, and which is used by YY_OBS_FREE to free the last string. */
44995b2e
AD
141
142static struct obstack string_obstack;
143char *last_string;
144
44995b2e
AD
145#define YY_OBS_GROW \
146 obstack_grow (&string_obstack, yytext, yyleng)
147
148#define YY_OBS_FINISH \
149 do { \
150 obstack_1grow (&string_obstack, '\0'); \
151 last_string = obstack_finish (&string_obstack); \
44995b2e
AD
152 } while (0)
153
154#define YY_OBS_FREE \
155 do { \
156 obstack_free (&string_obstack, last_string); \
157 } while (0)
e9955c83 158
4cdb01db
AD
159void
160scanner_last_string_free (void)
161{
162 YY_OBS_FREE;
163}
164
165
e9955c83
AD
166static int braces_level = 0;
167static int percent_percent_count = 0;
168
efcb44dd
PE
169/* Within well-formed rules, RULE_LENGTH is the number of values in
170 the current rule so far, which says where to find `$0' with respect
171 to the top of the stack. It is not the same as the rule->length in
172 the case of mid rule actions.
173
174 Outside of well-formed rules, RULE_LENGTH has an undefined value. */
175static int rule_length;
176
d33cb3ae
PE
177static void handle_dollar (braced_code_t code_kind,
178 char *cp, location_t location);
179static void handle_at (braced_code_t code_kind,
180 char *cp, location_t location);
d8d3f94a 181static int convert_ucn_to_byte (char const *hex_text);
e9955c83
AD
182
183%}
d8d3f94a 184%x SC_COMMENT SC_LINE_COMMENT SC_YACC_COMMENT
e9955c83
AD
185%x SC_STRING SC_CHARACTER
186%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
187%x SC_BRACED_CODE SC_PROLOGUE SC_EPILOGUE
188
d8d3f94a
PE
189letter [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
190id {letter}({letter}|[0-9])*
e9955c83 191int [0-9]+
d8d3f94a
PE
192
193/* POSIX says that a tag must be both an id and a C union member, but
194 historically almost any character is allowed in a tag. We disallow
195 NUL and newline, as this simplifies our implementation. */
196tag [^\0\n>]+
197
198/* Zero or more instances of backslash-newline. Following GCC, allow
199 white space between the backslash and the newline. */
200splice (\\[ \f\t\v]*\n)*
e9955c83
AD
201
202%%
203%{
204 /* At each yylex invocation, mark the current position as the
205 start of the next token. */
e9955c83 206 YY_STEP;
e9955c83
AD
207%}
208
209
210 /*----------------------------.
211 | Scanning Bison directives. |
212 `----------------------------*/
213<INITIAL>
214{
215 "%binary" return PERCENT_NONASSOC;
216 "%debug" return PERCENT_DEBUG;
217 "%define" return PERCENT_DEFINE;
218 "%defines" return PERCENT_DEFINES;
9280d3ef 219 "%destructor" return PERCENT_DESTRUCTOR;
676385e2 220 "%dprec" return PERCENT_DPREC;
e9955c83
AD
221 "%error"[-_]"verbose" return PERCENT_ERROR_VERBOSE;
222 "%expect" return PERCENT_EXPECT;
223 "%file-prefix" return PERCENT_FILE_PREFIX;
224 "%fixed"[-_]"output"[-_]"files" return PERCENT_YACC;
ae7453f2 225 "%glr-parser" return PERCENT_GLR_PARSER;
e9955c83
AD
226 "%left" return PERCENT_LEFT;
227 "%locations" return PERCENT_LOCATIONS;
676385e2 228 "%merge" return PERCENT_MERGE;
e9955c83
AD
229 "%name"[-_]"prefix" return PERCENT_NAME_PREFIX;
230 "%no"[-_]"lines" return PERCENT_NO_LINES;
231 "%nonassoc" return PERCENT_NONASSOC;
232 "%nterm" return PERCENT_NTERM;
233 "%output" return PERCENT_OUTPUT;
ae7453f2 234 "%parse-param" return PERCENT_PARSE_PARAM;
d8d3f94a 235 "%prec" rule_length--; return PERCENT_PREC;
366eea36 236 "%printer" return PERCENT_PRINTER;
e9955c83
AD
237 "%pure"[-_]"parser" return PERCENT_PURE_PARSER;
238 "%right" return PERCENT_RIGHT;
ae7453f2 239 "%lex-param" return PERCENT_LEX_PARAM;
e9955c83
AD
240 "%skeleton" return PERCENT_SKELETON;
241 "%start" return PERCENT_START;
242 "%term" return PERCENT_TOKEN;
243 "%token" return PERCENT_TOKEN;
244 "%token"[-_]"table" return PERCENT_TOKEN_TABLE;
245 "%type" return PERCENT_TYPE;
246 "%union" return PERCENT_UNION;
247 "%verbose" return PERCENT_VERBOSE;
248 "%yacc" return PERCENT_YACC;
249
250 "=" return EQUAL;
d8d3f94a
PE
251 ":" rule_length = 0; return COLON;
252 "|" rule_length = 0; return PIPE;
ae7453f2 253 "," return COMMA;
e9955c83
AD
254 ";" return SEMICOLON;
255
d8d3f94a
PE
256 [ \f\n\t\v]+ YY_STEP;
257
e9955c83 258 {id} {
39f41916 259 yylval->symbol = symbol_get (yytext, *yylloc);
efcb44dd 260 rule_length++;
e9955c83
AD
261 return ID;
262 }
263
d8d3f94a
PE
264 {int} {
265 unsigned long num;
266 errno = 0;
267 num = strtoul (yytext, 0, 10);
268 if (INT_MAX < num || errno)
269 {
c4d720cd 270 complain_at (*yylloc, _("invalid value: %s"), quote (yytext));
d8d3f94a
PE
271 num = INT_MAX;
272 }
273 yylval->integer = num;
274 return INT;
275 }
e9955c83
AD
276
277 /* Characters. We don't check there is only one. */
db2cc12f 278 "'" YY_OBS_GROW; yy_push_state (SC_ESCAPED_CHARACTER);
e9955c83
AD
279
280 /* Strings. */
db2cc12f 281 "\"" YY_OBS_GROW; yy_push_state (SC_ESCAPED_STRING);
e9955c83
AD
282
283 /* Comments. */
d8d3f94a 284 "/*" BEGIN SC_YACC_COMMENT;
e9955c83
AD
285 "//".* YY_STEP;
286
287 /* Prologue. */
1d6412ad 288 "%{" yy_push_state (SC_PROLOGUE);
e9955c83
AD
289
290 /* Code in between braces. */
1d6412ad 291 "{" YY_OBS_GROW; ++braces_level; yy_push_state (SC_BRACED_CODE);
e9955c83
AD
292
293 /* A type. */
d8d3f94a 294 "<"{tag}">" {
4cdb01db
AD
295 obstack_grow (&string_obstack, yytext + 1, yyleng - 2);
296 YY_OBS_FINISH;
297 yylval->string = last_string;
298 return TYPE;
299 }
300
e9955c83
AD
301
302 "%%" {
303 if (++percent_percent_count == 2)
304 yy_push_state (SC_EPILOGUE);
305 return PERCENT_PERCENT;
306 }
307
308 . {
c4d720cd 309 complain_at (*yylloc, _("invalid character: %s"), quote (yytext));
e9955c83
AD
310 YY_STEP;
311 }
312}
313
314
d8d3f94a
PE
315 /*-------------------------------------------------------------------.
316 | Whatever the start condition (but those which correspond to |
317 | entities `swallowed' by Bison: SC_YACC_COMMENT, SC_ESCAPED_STRING, |
318 | and SC_ESCAPED_CHARACTER), no M4 character must escape as is. |
319 `-------------------------------------------------------------------*/
e9955c83 320
d8d3f94a 321<SC_COMMENT,SC_LINE_COMMENT,SC_STRING,SC_CHARACTER,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
e9955c83 322{
d8d3f94a
PE
323 \[ obstack_sgrow (&string_obstack, "@<:@");
324 \] obstack_sgrow (&string_obstack, "@:>@");
e9955c83
AD
325}
326
327
d8d3f94a
PE
328 /*---------------------------------------------------------------.
329 | Scanning a Yacc comment. The initial `/ *' is already eaten. |
330 `---------------------------------------------------------------*/
e9955c83 331
d8d3f94a 332<SC_YACC_COMMENT>
e9955c83 333{
d8d3f94a
PE
334 "*/" {
335 YY_STEP;
336 BEGIN INITIAL;
e9955c83
AD
337 }
338
d8d3f94a
PE
339 [^*]+|"*" ;
340
341 <<EOF>> {
c4d720cd 342 complain_at (*yylloc, _("unexpected end of file in a comment"));
d8d3f94a
PE
343 BEGIN INITIAL;
344 }
345}
346
347
348 /*------------------------------------------------------------.
349 | Scanning a C comment. The initial `/ *' is already eaten. |
350 `------------------------------------------------------------*/
351
352<SC_COMMENT>
353{
354 "*"{splice}"/" YY_OBS_GROW; yy_pop_state ();
355 [^*\[\]]+|"*" YY_OBS_GROW;
e9955c83
AD
356
357 <<EOF>> {
c4d720cd 358 complain_at (*yylloc, _("unexpected end of file in a comment"));
e9955c83
AD
359 yy_pop_state ();
360 }
361}
362
363
d8d3f94a
PE
364 /*--------------------------------------------------------------.
365 | Scanning a line comment. The initial `//' is already eaten. |
366 `--------------------------------------------------------------*/
367
368<SC_LINE_COMMENT>
369{
370 "\n" YY_OBS_GROW; yy_pop_state ();
371 ([^\n\[\]]|{splice})+ YY_OBS_GROW;
372 <<EOF>> yy_pop_state ();
373}
374
375
e9955c83
AD
376 /*----------------------------------------------------------------.
377 | Scanning a C string, including its escapes. The initial `"' is |
378 | already eaten. |
379 `----------------------------------------------------------------*/
380
381<SC_ESCAPED_STRING>
382{
db2cc12f 383 "\"" {
e9955c83 384 assert (yy_top_state () == INITIAL);
44995b2e
AD
385 YY_OBS_GROW;
386 YY_OBS_FINISH;
4cdb01db 387 yylval->string = last_string;
e9955c83 388 yy_pop_state ();
efcb44dd 389 rule_length++;
e9955c83
AD
390 return STRING;
391 }
392
d8d3f94a 393 [^\"\\]+ YY_OBS_GROW;
e9955c83
AD
394
395 <<EOF>> {
c4d720cd 396 complain_at (*yylloc, _("unexpected end of file in a string"));
e9955c83 397 assert (yy_top_state () == INITIAL);
44995b2e 398 YY_OBS_FINISH;
4cdb01db 399 yylval->string = last_string;
e9955c83
AD
400 yy_pop_state ();
401 return STRING;
402 }
403}
404
405 /*---------------------------------------------------------------.
406 | Scanning a C character, decoding its escapes. The initial "'" |
407 | is already eaten. |
408 `---------------------------------------------------------------*/
409
410<SC_ESCAPED_CHARACTER>
411{
db2cc12f 412 "'" {
44995b2e 413 YY_OBS_GROW;
e9955c83
AD
414 assert (yy_top_state () == INITIAL);
415 {
44995b2e 416 YY_OBS_FINISH;
39f41916 417 yylval->symbol = symbol_get (last_string, *yylloc);
e776192e 418 symbol_class_set (yylval->symbol, token_sym, *yylloc);
e68d4575
PE
419 symbol_user_token_number_set (yylval->symbol,
420 (unsigned char) last_string[1], *yylloc);
44995b2e 421 YY_OBS_FREE;
e9955c83 422 yy_pop_state ();
efcb44dd 423 rule_length++;
e9955c83
AD
424 return ID;
425 }
426 }
427
c4d720cd 428 [^\'\\]+ YY_OBS_GROW;
e9955c83
AD
429
430 <<EOF>> {
c4d720cd 431 complain_at (*yylloc, _("unexpected end of file in a character"));
e9955c83 432 assert (yy_top_state () == INITIAL);
44995b2e 433 YY_OBS_FINISH;
4cdb01db 434 yylval->string = last_string;
e9955c83
AD
435 yy_pop_state ();
436 return CHARACTER;
437 }
438}
439
440
441 /*----------------------------.
442 | Decode escaped characters. |
443 `----------------------------*/
444
445<SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
446{
d8d3f94a
PE
447 \\[0-7]{1,3} {
448 unsigned long c = strtoul (yytext + 1, 0, 8);
449 if (UCHAR_MAX < c)
e9955c83 450 {
c4d720cd 451 complain_at (*yylloc, _("invalid escape: %s"), quote (yytext));
e9955c83
AD
452 YY_STEP;
453 }
454 else
455 obstack_1grow (&string_obstack, c);
456 }
457
d8d3f94a
PE
458 \\x[0-9a-fA-F]+ {
459 unsigned long c;
460 errno = 0;
461 c = strtoul (yytext + 2, 0, 16);
462 if (UCHAR_MAX < c || errno)
463 {
c4d720cd 464 complain_at (*yylloc, _("invalid escape: %s"), quote (yytext));
d8d3f94a
PE
465 YY_STEP;
466 }
467 else
468 obstack_1grow (&string_obstack, c);
e9955c83
AD
469 }
470
471 \\a obstack_1grow (&string_obstack, '\a');
472 \\b obstack_1grow (&string_obstack, '\b');
473 \\f obstack_1grow (&string_obstack, '\f');
474 \\n obstack_1grow (&string_obstack, '\n');
475 \\r obstack_1grow (&string_obstack, '\r');
476 \\t obstack_1grow (&string_obstack, '\t');
477 \\v obstack_1grow (&string_obstack, '\v');
c4d720cd 478 \\[\"\'?\\] obstack_1grow (&string_obstack, yytext[1]);
d8d3f94a
PE
479 \\(u|U[0-9a-fA-F]{4})[0-9a-fA-F]{4} {
480 int c = convert_ucn_to_byte (yytext);
481 if (c < 0)
482 {
c4d720cd 483 complain_at (*yylloc, _("invalid escape: %s"), quote (yytext));
d8d3f94a
PE
484 YY_STEP;
485 }
486 else
487 obstack_1grow (&string_obstack, c);
488 }
4f25ebb0 489 \\(.|\n) {
c4d720cd 490 complain_at (*yylloc, _("unrecognized escape: %s"), quote (yytext));
44995b2e 491 YY_OBS_GROW;
e9955c83 492 }
4f25ebb0
AD
493 /* FLex wants this rule, in case of a `\<<EOF>>'. */
494 \\ YY_OBS_GROW;
e9955c83
AD
495}
496
497
498 /*----------------------------------------------------------.
499 | Scanning a C character without decoding its escapes. The |
500 | initial "'" is already eaten. |
501 `----------------------------------------------------------*/
502
503<SC_CHARACTER>
504{
db2cc12f 505 "'" {
44995b2e 506 YY_OBS_GROW;
e9955c83
AD
507 assert (yy_top_state () != INITIAL);
508 yy_pop_state ();
509 }
510
d8d3f94a
PE
511 [^'\[\]\\]+ YY_OBS_GROW;
512 \\{splice}[^\[\]] YY_OBS_GROW;
513 {splice} YY_OBS_GROW;
514 /* Needed for `\<<EOF>>', `\\<<newline>>[', and `\\<<newline>>]'. */
4f25ebb0 515 \\ YY_OBS_GROW;
e9955c83 516
e9955c83 517 <<EOF>> {
c4d720cd 518 complain_at (*yylloc, _("unexpected end of file in a character"));
e9955c83
AD
519 assert (yy_top_state () != INITIAL);
520 yy_pop_state ();
521 }
522}
523
524
525 /*----------------------------------------------------------------.
526 | Scanning a C string, without decoding its escapes. The initial |
527 | `"' is already eaten. |
528 `----------------------------------------------------------------*/
529
530<SC_STRING>
531{
db2cc12f 532 "\"" {
e9955c83 533 assert (yy_top_state () != INITIAL);
44995b2e 534 YY_OBS_GROW;
e9955c83
AD
535 yy_pop_state ();
536 }
537
d8d3f94a
PE
538 [^\"\[\]\\]+ YY_OBS_GROW;
539 \\{splice}[^\[\]] YY_OBS_GROW;
540 {splice} YY_OBS_GROW;
541 /* Needed for `\<<EOF>>', `\\<<newline>>[', and `\\<<newline>>]'. */
4f25ebb0 542 \\ YY_OBS_GROW;
e9955c83 543
e9955c83 544 <<EOF>> {
c4d720cd 545 complain_at (*yylloc, _("unexpected end of file in a string"));
e9955c83
AD
546 assert (yy_top_state () != INITIAL);
547 yy_pop_state ();
548 }
549}
550
551
552 /*---------------------------------------------------.
553 | Strings, comments etc. can be found in user code. |
554 `---------------------------------------------------*/
555
556<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
557{
558 /* Characters. We don't check there is only one. */
db2cc12f 559 "'" YY_OBS_GROW; yy_push_state (SC_CHARACTER);
e9955c83
AD
560
561 /* Strings. */
db2cc12f 562 "\"" YY_OBS_GROW; yy_push_state (SC_STRING);
e9955c83
AD
563
564 /* Comments. */
d8d3f94a
PE
565 "/"{splice}"*" YY_OBS_GROW; yy_push_state (SC_COMMENT);
566 "/"{splice}"/" YY_OBS_GROW; yy_push_state (SC_LINE_COMMENT);
4f25ebb0
AD
567
568 /* Not comments. */
569 "/" YY_OBS_GROW;
e9955c83
AD
570}
571
572
573 /*---------------------------------------------------------------.
574 | Scanning some code in braces (%union and actions). The initial |
575 | "{" is already eaten. |
576 `---------------------------------------------------------------*/
577
578<SC_BRACED_CODE>
579{
580 "}" {
44995b2e 581 YY_OBS_GROW;
e9955c83
AD
582 if (--braces_level == 0)
583 {
584 yy_pop_state ();
44995b2e 585 YY_OBS_FINISH;
4cdb01db 586 yylval->string = last_string;
efcb44dd 587 rule_length++;
e9955c83
AD
588 return BRACED_CODE;
589 }
590 }
591
44995b2e 592 "{" YY_OBS_GROW; braces_level++;
e9955c83 593
d8d3f94a 594 "$"("<"{tag}">")?(-?[0-9]+|"$") { handle_dollar (current_braced_code,
f25bfb75
AD
595 yytext, *yylloc); }
596 "@"(-?[0-9]+|"$") { handle_at (current_braced_code,
597 yytext, *yylloc); }
e9955c83 598
c4d720cd 599 [^$@\[\]/\'\"\{\}]+ YY_OBS_GROW;
e9955c83 600
d8d3f94a 601 /* A stray $, or /, or etc. */
44995b2e 602 . YY_OBS_GROW;
e9955c83
AD
603
604 <<EOF>> {
c4d720cd 605 complain_at (*yylloc, _("unexpected end of file in a braced code"));
e9955c83 606 yy_pop_state ();
44995b2e 607 YY_OBS_FINISH;
4cdb01db
AD
608 yylval->string = last_string;
609 return BRACED_CODE;
e9955c83
AD
610 }
611
612}
613
614
615 /*--------------------------------------------------------------.
616 | Scanning some prologue: from "%{" (already scanned) to "%}". |
617 `--------------------------------------------------------------*/
618
619<SC_PROLOGUE>
620{
621 "%}" {
622 yy_pop_state ();
44995b2e 623 YY_OBS_FINISH;
4cdb01db 624 yylval->string = last_string;
e9955c83
AD
625 return PROLOGUE;
626 }
627
c4d720cd 628 [^%\[\]/\'\"]+ YY_OBS_GROW;
4f25ebb0 629 "%" YY_OBS_GROW;
e9955c83
AD
630
631 <<EOF>> {
c4d720cd 632 complain_at (*yylloc, _("unexpected end of file in a prologue"));
e9955c83 633 yy_pop_state ();
44995b2e 634 YY_OBS_FINISH;
4cdb01db 635 yylval->string = last_string;
e9955c83
AD
636 return PROLOGUE;
637 }
e9955c83
AD
638}
639
640
641 /*---------------------------------------------------------------.
642 | Scanning the epilogue (everything after the second "%%", which |
d8d3f94a 643 | has already been eaten). |
e9955c83
AD
644 `---------------------------------------------------------------*/
645
646<SC_EPILOGUE>
647{
d8d3f94a 648 [^\[\]]+ YY_OBS_GROW;
e9955c83
AD
649
650 <<EOF>> {
651 yy_pop_state ();
44995b2e 652 YY_OBS_FINISH;
4cdb01db 653 yylval->string = last_string;
e9955c83
AD
654 return EPILOGUE;
655 }
656}
657
658
659%%
660
661/*------------------------------------------------------------------.
366eea36 662| TEXT is pointing to a wannabee semantic value (i.e., a `$'). |
e9955c83
AD
663| |
664| Possible inputs: $[<TYPENAME>]($|integer) |
665| |
666| Output to the STRING_OBSTACK a reference to this semantic value. |
667`------------------------------------------------------------------*/
668
f25bfb75 669static inline void
366eea36 670handle_action_dollar (char *text, location_t location)
e9955c83
AD
671{
672 const char *type_name = NULL;
366eea36 673 char *cp = text + 1;
e9955c83
AD
674
675 /* Get the type name if explicit. */
676 if (*cp == '<')
677 {
678 type_name = ++cp;
679 while (*cp != '>')
680 ++cp;
681 *cp = '\0';
682 ++cp;
683 }
684
685 if (*cp == '$')
686 {
687 if (!type_name)
56c47203 688 type_name = symbol_list_n_type_name_get (current_rule, location, 0);
e9955c83 689 if (!type_name && typed)
56c47203 690 complain_at (location, _("$$ of `%s' has no declared type"),
97650f4e 691 current_rule->sym->tag);
e9955c83
AD
692 if (!type_name)
693 type_name = "";
694 obstack_fgrow1 (&string_obstack,
695 "]b4_lhs_value([%s])[", type_name);
696 }
d8d3f94a 697 else
e9955c83 698 {
d8d3f94a
PE
699 long num;
700 errno = 0;
701 num = strtol (cp, 0, 10);
e9955c83 702
d8d3f94a 703 if (INT_MIN <= num && num <= rule_length && ! errno)
e9955c83 704 {
d8d3f94a 705 int n = num;
e9955c83 706 if (!type_name && n > 0)
56c47203
AD
707 type_name = symbol_list_n_type_name_get (current_rule, location,
708 n);
e9955c83 709 if (!type_name && typed)
56c47203 710 complain_at (location, _("$%d of `%s' has no declared type"),
97650f4e 711 n, current_rule->sym->tag);
e9955c83
AD
712 if (!type_name)
713 type_name = "";
714 obstack_fgrow3 (&string_obstack,
715 "]b4_rhs_value([%d], [%d], [%s])[",
716 rule_length, n, type_name);
717 }
d8d3f94a 718 else
c4d720cd 719 complain_at (location, _("invalid value: %s"), quote (text));
9280d3ef
AD
720 }
721}
722
723
366eea36 724/*---------------------------------------------------------------.
d8d3f94a 725| TEXT is expected to be $$ in some code associated to a symbol: |
366eea36
AD
726| destructor or printer. |
727`---------------------------------------------------------------*/
9280d3ef 728
f25bfb75 729static inline void
366eea36 730handle_symbol_code_dollar (char *text, location_t location)
9280d3ef 731{
366eea36 732 char *cp = text + 1;
9280d3ef 733 if (*cp == '$')
366eea36 734 obstack_sgrow (&string_obstack, "]b4_dollar_dollar[");
9280d3ef 735 else
c4d720cd 736 complain_at (location, _("invalid value: %s"), quote (text));
e9955c83
AD
737}
738
f25bfb75
AD
739
740/*-----------------------------------------------------------------.
741| Dispatch onto handle_action_dollar, or handle_destructor_dollar, |
742| depending upon CODE_KIND. |
743`-----------------------------------------------------------------*/
e9955c83
AD
744
745static void
f25bfb75
AD
746handle_dollar (braced_code_t braced_code_kind,
747 char *text, location_t location)
748{
749 switch (braced_code_kind)
750 {
751 case action_braced_code:
752 handle_action_dollar (text, location);
753 break;
754
755 case destructor_braced_code:
366eea36
AD
756 case printer_braced_code:
757 handle_symbol_code_dollar (text, location);
f25bfb75
AD
758 break;
759 }
760}
761
762
763/*------------------------------------------------------.
764| TEXT is a location token (i.e., a `@...'). Output to |
765| STRING_OBSTACK a reference to this location. |
766`------------------------------------------------------*/
767
768static inline void
769handle_action_at (char *text, location_t location)
e9955c83 770{
366eea36 771 char *cp = text + 1;
e9955c83 772 locations_flag = 1;
e9955c83 773
366eea36 774 if (*cp == '$')
e9955c83
AD
775 {
776 obstack_sgrow (&string_obstack, "]b4_lhs_location[");
777 }
d8d3f94a 778 else
e9955c83 779 {
d8d3f94a
PE
780 long num;
781 errno = 0;
782 num = strtol (cp, 0, 10);
dafdc66f 783
d8d3f94a
PE
784 if (INT_MIN <= num && num <= rule_length && ! errno)
785 {
786 int n = num;
787 obstack_fgrow2 (&string_obstack, "]b4_rhs_location([%d], [%d])[",
788 rule_length, n);
789 }
e9955c83 790 else
c4d720cd 791 complain_at (location, _("invalid value: %s"), quote (text));
f25bfb75
AD
792 }
793}
794
795
366eea36 796/*---------------------------------------------------------------.
d8d3f94a 797| TEXT is expected to be @$ in some code associated to a symbol: |
366eea36
AD
798| destructor or printer. |
799`---------------------------------------------------------------*/
f25bfb75
AD
800
801static inline void
366eea36 802handle_symbol_code_at (char *text, location_t location)
f25bfb75 803{
366eea36
AD
804 char *cp = text + 1;
805 if (*cp == '$')
806 obstack_sgrow (&string_obstack, "]b4_at_dollar[");
f25bfb75 807 else
c4d720cd 808 complain_at (location, _("invalid value: %s"), quote (text));
e9955c83 809}
4cdb01db 810
f25bfb75
AD
811
812/*-------------------------------------------------------------------.
813| Dispatch onto handle_action_at, or handle_destructor_at, depending |
814| upon CODE_KIND. |
815`-------------------------------------------------------------------*/
816
817static void
818handle_at (braced_code_t braced_code_kind,
819 char *text, location_t location)
820{
821 switch (braced_code_kind)
822 {
823 case action_braced_code:
824 handle_action_at (text, location);
825 break;
826
827 case destructor_braced_code:
366eea36
AD
828 case printer_braced_code:
829 handle_symbol_code_at (text, location);
f25bfb75
AD
830 break;
831 }
832}
833
834
d8d3f94a
PE
835/*------------------------------------------------------------------.
836| Convert universal character name UCN to a single-byte character, |
837| and return that character. Return -1 if UCN does not correspond |
838| to a single-byte character. |
839`------------------------------------------------------------------*/
840
841static int
842convert_ucn_to_byte (char const *ucn)
843{
844 unsigned long code = strtoul (ucn + 2, 0, 16);
845
846 /* FIXME: Currently we assume Unicode-compatible unibyte characters
847 on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes). On
848 non-ASCII hosts we support only the portable C character set.
849 These limitations should be removed once we add support for
850 multibyte characters. */
851
852 if (UCHAR_MAX < code)
853 return -1;
854
855#if ! ('$' == 0x24 && '@' == 0x40 && '`' == 0x60 && '~' == 0x7e)
856 {
857 /* A non-ASCII host. Use CODE to index into a table of the C
858 basic execution character set, which is guaranteed to exist on
859 all Standard C platforms. This table also includes '$', '@',
860 and '`', which not in the basic execution character set but
861 which are unibyte characters on all the platforms that we know
862 about. */
863 static signed char const table[] =
864 {
865 '\0', -1, -1, -1, -1, -1, -1, '\a',
866 '\b', '\t', '\n', '\v', '\f', '\r', -1, -1,
867 -1, -1, -1, -1, -1, -1, -1, -1,
868 -1, -1, -1, -1, -1, -1, -1, -1,
869 ' ', '!', '"', '#', '$', '%', '&', '\'',
870 '(', ')', '*', '+', ',', '-', '.', '/',
871 '0', '1', '2', '3', '4', '5', '6', '7',
872 '8', '9', ':', ';', '<', '=', '>', '?',
873 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
874 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
875 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
876 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
877 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
878 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
879 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
880 'x', 'y', 'z', '{', '|', '}', '~'
881 };
882
883 code = code < sizeof table ? table[code] : -1;
884 }
885#endif
c4d720cd 886
d8d3f94a
PE
887 return code;
888}
889
890
f25bfb75
AD
891/*-------------------------.
892| Initialize the scanner. |
893`-------------------------*/
894
1d6412ad
AD
895void
896scanner_initialize (void)
897{
898 obstack_init (&string_obstack);
899}
900
901
f25bfb75
AD
902/*-----------------------------------------------.
903| Free all the memory allocated to the scanner. |
904`-----------------------------------------------*/
905
4cdb01db
AD
906void
907scanner_free (void)
908{
909 obstack_free (&string_obstack, 0);
536545f3
AD
910 /* Reclaim Flex's buffers. */
911 yy_delete_buffer (YY_CURRENT_BUFFER);
4cdb01db 912}