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