Simplify handling of '.' and '-' after unbracketed named references.
[bison.git] / src / scan-gram.l
bloba40aadeaf509406439861a6997fbaecfd4873df6
1 /* Bison Grammar Scanner                             -*- C -*-
3    Copyright (C) 2002-2011 Free Software Foundation, Inc.
5    This file is part of Bison, the GNU Compiler Compiler.
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20 %option debug nodefault noinput nounput noyywrap never-interactive
21 %option prefix="gram_" outfile="lex.yy.c"
24 /* Work around a bug in flex 2.5.31.  See Debian bug 333231
25    <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.  */
26 #undef gram_wrap
27 #define gram_wrap() 1
29 #define FLEX_PREFIX(Id) gram_ ## Id
30 #include <src/flex-scanner.h>
32 #include <src/complain.h>
33 #include <src/files.h>
34 #include <src/gram.h>
35 #include <quotearg.h>
36 #include <src/reader.h>
37 #include <src/uniqstr.h>
39 #include <ctype.h>
40 #include <mbswidth.h>
41 #include <quote.h>
43 #include <src/scan-gram.h>
45 #define YY_DECL GRAM_LEX_DECL
47 #define YY_USER_INIT                                    \
48    code_start = scanner_cursor = loc->start;            \
50 /* Location of scanner cursor.  */
51 static boundary scanner_cursor;
53 #define YY_USER_ACTION  location_compute (loc, &scanner_cursor, yytext, yyleng);
55 static size_t no_cr_read (FILE *, char *, size_t);
56 #define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
58 #define RETURN_PERCENT_PARAM(Value)                     \
59   RETURN_VALUE(PERCENT_PARAM, param, param_ ## Value)
61 #define RETURN_PERCENT_FLAG(Value)                              \
62   RETURN_VALUE(PERCENT_FLAG, uniqstr, uniqstr_new (Value))
64 #define RETURN_VALUE(Token, Field, Value)       \
65   do {                                          \
66     val->Field = Value;                         \
67     return Token;                               \
68   } while (0)
70 #define ROLLBACK_CURRENT_TOKEN                                  \
71   do {                                                          \
72     scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);     \
73     yyless (0);                                                 \
74   } while (0)
76 /* A string representing the most recently saved token.  */
77 static char *last_string;
79 /* Bracketed identifier. */
80 static uniqstr bracketed_id_str = 0;
81 static location bracketed_id_loc;
82 static boundary bracketed_id_start;
83 static int bracketed_id_context_state = 0;
85 void
86 gram_scanner_last_string_free (void)
88   STRING_FREE;
91 static void handle_syncline (char *, location);
92 static unsigned long int scan_integer (char const *p, int base, location loc);
93 static int convert_ucn_to_byte (char const *hex_text);
94 static void unexpected_eof (boundary, char const *);
95 static void unexpected_newline (boundary, char const *);
98  /* A C-like comment in directives/rules. */
99 %x SC_YACC_COMMENT
100  /* Strings and characters in directives/rules. */
101 %x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
102  /* A identifier was just read in directives/rules.  Special state
103     to capture the sequence `identifier :'. */
104 %x SC_AFTER_IDENTIFIER
105  /* A complex tag, with nested angles brackets. */
106 %x SC_TAG
108  /* Four types of user code:
109     - prologue (code between `%{' `%}' in the first section, before %%);
110     - actions, printers, union, etc, (between braced in the middle section);
111     - epilogue (everything after the second %%). 
112     - predicate (code between `%?{' and `{' in middle section); */
113 %x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE SC_PREDICATE
114  /* C and C++ comments in code. */
115 %x SC_COMMENT SC_LINE_COMMENT
116  /* Strings and characters in code. */
117 %x SC_STRING SC_CHARACTER
118  /* Bracketed identifiers support. */
119 %x SC_BRACKETED_ID SC_RETURN_BRACKETED_ID
121 /* A Bison identifier.  Keep this synchronized with scan-code.l "id".  */
122 letter    [-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
123 id        {letter}({letter}|[0-9])*
124 directive %{id}
125 int       [0-9]+
127 /* POSIX says that a tag must be both an id and a C union member, but
128    historically almost any character is allowed in a tag.  We disallow
129    NUL, as this simplifies our implementation.  We disallow angle
130    bracket to match them in nested pairs: several languages use them
131    for generics/template types.  */
132 tag      [^\0<>]+
134 /* Zero or more instances of backslash-newline.  Following GCC, allow
135    white space between the backslash and the newline.  */
136 splice   (\\[ \f\t\v]*\n)*
140   /* Nesting level.  Either for nested braces, or nested angle brackets
141      (but not mixed).  */
142   int nesting IF_LINT (= 0);
144   /* Parent context state, when applicable.  */
145   int context_state IF_LINT (= 0);
147   /* Location of most recent identifier, when applicable.  */
148   location id_loc IF_LINT (= empty_location);
150   /* Where containing code started, when applicable.  Its initial
151      value is relevant only when yylex is invoked in the SC_EPILOGUE
152      start condition.  */
153   boundary code_start = scanner_cursor;
155   /* Where containing comment or string or character literal started,
156      when applicable.  */
157   boundary token_start IF_LINT (= scanner_cursor);
161   /*-----------------------.
162   | Scanning white space.  |
163   `-----------------------*/
165 <INITIAL,SC_AFTER_IDENTIFIER,SC_BRACKETED_ID,SC_RETURN_BRACKETED_ID>
167   /* Comments and white space.  */
168   ","          warn_at (*loc, _("stray `,' treated as white space"));
169   [ \f\n\t\v]  |
170   "//".*       ;
171   "/*" {
172     token_start = loc->start;
173     context_state = YY_START;
174     BEGIN SC_YACC_COMMENT;
175   }
177   /* #line directives are not documented, and may be withdrawn or
178      modified in future versions of Bison.  */
179   ^"#line "{int}" \"".*"\"\n" {
180     handle_syncline (yytext + sizeof "#line " - 1, *loc);
181   }
185   /*----------------------------.
186   | Scanning Bison directives.  |
187   `----------------------------*/
189   /* For directives that are also command line options, the regex must be
190         "%..."
191      after "[-_]"s are removed, and the directive must match the --long
192      option name, with a single string argument.  Otherwise, add exceptions
193      to ../build-aux/cross-options.pl.  */
195 <INITIAL>
197   "%binary"                         return PERCENT_NONASSOC;
198   "%code"                           return PERCENT_CODE;
199   "%debug"                          RETURN_PERCENT_FLAG("parse.trace");
200   "%default"[-_]"prec"              return PERCENT_DEFAULT_PREC;
201   "%define"                         return PERCENT_DEFINE;
202   "%defines"                        return PERCENT_DEFINES;
203   "%destructor"                     return PERCENT_DESTRUCTOR;
204   "%dprec"                          return PERCENT_DPREC;
205   "%error"[-_]"verbose"             return PERCENT_ERROR_VERBOSE;
206   "%expect"                         return PERCENT_EXPECT;
207   "%expect"[-_]"rr"                 return PERCENT_EXPECT_RR;
208   "%file-prefix"                    return PERCENT_FILE_PREFIX;
209   "%fixed"[-_]"output"[-_]"files"   return PERCENT_YACC;
210   "%initial-action"                 return PERCENT_INITIAL_ACTION;
211   "%glr-parser"                     return PERCENT_GLR_PARSER;
212   "%language"                       return PERCENT_LANGUAGE;
213   "%left"                           return PERCENT_LEFT;
214   "%lex-param"                      RETURN_PERCENT_PARAM(lex);
215   "%locations"                      RETURN_PERCENT_FLAG("locations");
216   "%merge"                          return PERCENT_MERGE;
217   "%name"[-_]"prefix"               return PERCENT_NAME_PREFIX;
218   "%no"[-_]"default"[-_]"prec"      return PERCENT_NO_DEFAULT_PREC;
219   "%no"[-_]"lines"                  return PERCENT_NO_LINES;
220   "%nonassoc"                       return PERCENT_NONASSOC;
221   "%nondeterministic-parser"        return PERCENT_NONDETERMINISTIC_PARSER;
222   "%nterm"                          return PERCENT_NTERM;
223   "%output"                         return PERCENT_OUTPUT;
224   "%param"                          RETURN_PERCENT_PARAM(both);
225   "%parse-param"                    RETURN_PERCENT_PARAM(parse);
226   "%prec"                           return PERCENT_PREC;
227   "%precedence"                     return PERCENT_PRECEDENCE;
228   "%printer"                        return PERCENT_PRINTER;
229   "%pure"[-_]"parser"               RETURN_PERCENT_FLAG("api.pure");
230   "%require"                        return PERCENT_REQUIRE;
231   "%right"                          return PERCENT_RIGHT;
232   "%skeleton"                       return PERCENT_SKELETON;
233   "%start"                          return PERCENT_START;
234   "%term"                           return PERCENT_TOKEN;
235   "%token"                          return PERCENT_TOKEN;
236   "%token"[-_]"table"               return PERCENT_TOKEN_TABLE;
237   "%type"                           return PERCENT_TYPE;
238   "%union"                          return PERCENT_UNION;
239   "%verbose"                        return PERCENT_VERBOSE;
240   "%yacc"                           return PERCENT_YACC;
242   {directive} {
243     complain_at (*loc, _("invalid directive: %s"), quote (yytext));
244   }
246   "="                     return EQUAL;
247   "|"                     return PIPE;
248   ";"                     return SEMICOLON;
250   {id} {
251     val->uniqstr = uniqstr_new (yytext);
252     id_loc = *loc;
253     bracketed_id_str = NULL;
254     BEGIN SC_AFTER_IDENTIFIER;
255   }
257   {int} {
258     val->integer = scan_integer (yytext, 10, *loc);
259     return INT;
260   }
261   0[xX][0-9abcdefABCDEF]+ {
262     val->integer = scan_integer (yytext, 16, *loc);
263     return INT;
264   }
266   /* Identifiers may not start with a digit.  Yet, don't silently
267      accept "1FOO" as "1 FOO".  */
268   {int}{id} {
269     complain_at (*loc, _("invalid identifier: %s"), quote (yytext));
270   }
272   /* Characters.  */
273   "'"         token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
275   /* Strings. */
276   "\""        token_start = loc->start; BEGIN SC_ESCAPED_STRING;
278   /* Prologue. */
279   "%{"        code_start = loc->start; BEGIN SC_PROLOGUE;
281   /* Code in between braces.  */
282   "{" {
283     STRING_GROW;
284     nesting = 0;
285     code_start = loc->start;
286     BEGIN SC_BRACED_CODE;
287   }
289   /* Semantic predicate. */
290   "%?"[ \f\n\t\v]*"{" {
291     nesting = 0;
292     code_start = loc->start;
293     BEGIN SC_PREDICATE;
294   }
296   /* A type. */
297   "<*>"       return TAG_ANY;
298   "<>"        return TAG_NONE;
299   "<"{tag}">" {
300     obstack_grow (&obstack_for_string, yytext + 1, yyleng - 2);
301     STRING_FINISH;
302     val->uniqstr = uniqstr_new (last_string);
303     STRING_FREE;
304     return TAG;
305   }
306   "<"         {
307     nesting = 0;
308     token_start = loc->start;
309     BEGIN SC_TAG;
310   }
312   "%%" {
313     static int percent_percent_count;
314     if (++percent_percent_count == 2)
315       BEGIN SC_EPILOGUE;
316     return PERCENT_PERCENT;
317   }
319   "[" {
320     bracketed_id_str = NULL;
321     bracketed_id_start = loc->start;
322     bracketed_id_context_state = YY_START;
323     BEGIN SC_BRACKETED_ID;
324   }
326   . {
327     complain_at (*loc, _("invalid character: %s"), quote (yytext));
328   }
330   <<EOF>> {
331     loc->start = loc->end = scanner_cursor;
332     yyterminate ();
333   }
337   /*--------------------------------------------------------------.
338   | Supporting \0 complexifies our implementation for no expected |
339   | added value.                                                  |
340   `--------------------------------------------------------------*/
342 <SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING,SC_TAG>
344   \0        complain_at (*loc, _("invalid null character"));
348   /*-----------------------------------------------------------------.
349   | Scanning after an identifier, checking whether a colon is next.  |
350   `-----------------------------------------------------------------*/
352 <SC_AFTER_IDENTIFIER>
354   "[" {
355     if (bracketed_id_str)
356       {
357         ROLLBACK_CURRENT_TOKEN;
358         BEGIN SC_RETURN_BRACKETED_ID;
359         *loc = id_loc;
360         return ID;
361       }
362     else
363       {
364         bracketed_id_start = loc->start;
365         bracketed_id_context_state = YY_START;
366         BEGIN SC_BRACKETED_ID;
367       }
368   }
369   ":" {
370     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
371     *loc = id_loc;
372     return ID_COLON;
373   }
374   . {
375     ROLLBACK_CURRENT_TOKEN;
376     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
377     *loc = id_loc;
378     return ID;
379   }
380   <<EOF>> {
381     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
382     *loc = id_loc;
383     return ID;
384   }
387   /*--------------------------------.
388   | Scanning bracketed identifiers. |
389   `--------------------------------*/
391 <SC_BRACKETED_ID>
393   {id} {
394     if (bracketed_id_str)
395       {
396         complain_at (*loc, _("unexpected identifier in bracketed name: %s"),
397                      quote (yytext));
398       }
399     else
400       {
401         bracketed_id_str = uniqstr_new (yytext);
402         bracketed_id_loc = *loc;
403       }
404   }
405   "]" {
406     BEGIN bracketed_id_context_state;
407     if (bracketed_id_str)
408       {
409         if (INITIAL == bracketed_id_context_state)
410           {
411             val->uniqstr = bracketed_id_str;
412             bracketed_id_str = 0;
413             *loc = bracketed_id_loc;
414             return BRACKETED_ID;
415           }
416       }
417     else
418       complain_at (*loc, _("an identifier expected"));
419   }
420   . {
421     complain_at (*loc, _("invalid character in bracketed name: %s"),
422                  quote (yytext));
423   }
424   <<EOF>> {
425     BEGIN bracketed_id_context_state;
426     unexpected_eof (bracketed_id_start, "]");
427   }
430 <SC_RETURN_BRACKETED_ID>
432   . {
433     ROLLBACK_CURRENT_TOKEN;
434     val->uniqstr = bracketed_id_str;
435     bracketed_id_str = 0;
436     *loc = bracketed_id_loc;
437     BEGIN INITIAL;
438     return BRACKETED_ID;
439   }
443   /*---------------------------------------------------------------.
444   | Scanning a Yacc comment.  The initial `/ *' is already eaten.  |
445   `---------------------------------------------------------------*/
447 <SC_YACC_COMMENT>
449   "*/"     BEGIN context_state;
450   .|\n     ;
451   <<EOF>>  unexpected_eof (token_start, "*/"); BEGIN context_state;
455   /*------------------------------------------------------------.
456   | Scanning a C comment.  The initial `/ *' is already eaten.  |
457   `------------------------------------------------------------*/
459 <SC_COMMENT>
461   "*"{splice}"/"  STRING_GROW; BEGIN context_state;
462   <<EOF>>         unexpected_eof (token_start, "*/"); BEGIN context_state;
466   /*--------------------------------------------------------------.
467   | Scanning a line comment.  The initial `//' is already eaten.  |
468   `--------------------------------------------------------------*/
470 <SC_LINE_COMMENT>
472   "\n"           STRING_GROW; BEGIN context_state;
473   {splice}       STRING_GROW;
474   <<EOF>>        BEGIN context_state;
478   /*------------------------------------------------.
479   | Scanning a Bison string, including its escapes. |
480   | The initial quote is already eaten.             |
481   `------------------------------------------------*/
483 <SC_ESCAPED_STRING>
485   "\""|"\n" {
486     if (yytext[0] == '\n')
487       unexpected_newline (token_start, "\"");
488     STRING_FINISH;
489     loc->start = token_start;
490     val->chars = last_string;
491     BEGIN INITIAL;
492     return STRING;
493   }
494   <<EOF>> {
495     unexpected_eof (token_start, "\"");
496     STRING_FINISH;
497     loc->start = token_start;
498     val->chars = last_string;
499     BEGIN INITIAL;
500     return STRING;
501   }
504   /*----------------------------------------------------------.
505   | Scanning a Bison character literal, decoding its escapes. |
506   | The initial quote is already eaten.                       |
507   `----------------------------------------------------------*/
509 <SC_ESCAPED_CHARACTER>
511   "'"|"\n" {
512     STRING_FINISH;
513     loc->start = token_start;
514     val->character = last_string[0];
515     {
516       /* FIXME: Eventually, make these errors.  */
517       if (last_string[0] == '\0')
518         {
519           warn_at (*loc, _("empty character literal"));
520           /* '\0' seems dangerous even if we are about to complain.  */
521           val->character = '\'';
522         }
523       else if (last_string[1] != '\0')
524         warn_at (*loc, _("extra characters in character literal"));
525     }
526     if (yytext[0] == '\n')
527       unexpected_newline (token_start, "'");
528     STRING_FREE;
529     BEGIN INITIAL;
530     return CHAR;
531   }
532   <<EOF>> {
533     STRING_FINISH;
534     loc->start = token_start;
535     val->character = last_string[0];
536     {
537       /* FIXME: Eventually, make these errors.  */
538       if (last_string[0] == '\0')
539         {
540           warn_at (*loc, _("empty character literal"));
541           /* '\0' seems dangerous even if we are about to complain.  */
542           val->character = '\'';
543         }
544       else if (last_string[1] != '\0')
545         warn_at (*loc, _("extra characters in character literal"));
546     }
547     unexpected_eof (token_start, "'");
548     STRING_FREE;
549     BEGIN INITIAL;
550     return CHAR;
551   }
554   /*-----------------------------------------------------------.
555   | Scanning a Bison nested tag.  The initial angle bracket is |
556   | already eaten.                                             |
557   `-----------------------------------------------------------*/
559 <SC_TAG>
561   ">" {
562     --nesting;
563     if (nesting < 0)
564       {
565         STRING_FINISH;
566         loc->start = token_start;
567         val->uniqstr = uniqstr_new (last_string);
568         STRING_FREE;
569         BEGIN INITIAL;
570         return TAG;
571       }
572     STRING_GROW;
573   }
575   [^<>]+ STRING_GROW;
576   "<"+   STRING_GROW; nesting += yyleng;
578   <<EOF>> {
579     unexpected_eof (token_start, ">");
580     STRING_FINISH;
581     loc->start = token_start;
582     val->uniqstr = uniqstr_new (last_string);
583     STRING_FREE;
584     BEGIN INITIAL;
585     return TAG;
586   }
589   /*----------------------------.
590   | Decode escaped characters.  |
591   `----------------------------*/
593 <SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
595   \\[0-7]{1,3} {
596     unsigned long int c = strtoul (yytext + 1, NULL, 8);
597     if (!c || UCHAR_MAX < c)
598       complain_at (*loc, _("invalid number after \\-escape: %s"),
599                    yytext+1);
600     else
601       obstack_1grow (&obstack_for_string, c);
602   }
604   \\x[0-9abcdefABCDEF]+ {
605     verify (UCHAR_MAX < ULONG_MAX);
606     unsigned long int c = strtoul (yytext + 2, NULL, 16);
607     if (!c || UCHAR_MAX < c)
608       complain_at (*loc, _("invalid number after \\-escape: %s"),
609                    yytext+1);
610     else
611       obstack_1grow (&obstack_for_string, c);
612   }
614   \\a   obstack_1grow (&obstack_for_string, '\a');
615   \\b   obstack_1grow (&obstack_for_string, '\b');
616   \\f   obstack_1grow (&obstack_for_string, '\f');
617   \\n   obstack_1grow (&obstack_for_string, '\n');
618   \\r   obstack_1grow (&obstack_for_string, '\r');
619   \\t   obstack_1grow (&obstack_for_string, '\t');
620   \\v   obstack_1grow (&obstack_for_string, '\v');
622   /* \\[\"\'?\\] would be shorter, but it confuses xgettext.  */
623   \\("\""|"'"|"?"|"\\")  obstack_1grow (&obstack_for_string, yytext[1]);
625   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
626     int c = convert_ucn_to_byte (yytext);
627     if (c <= 0)
628       complain_at (*loc, _("invalid number after \\-escape: %s"),
629                    yytext+1);
630     else
631       obstack_1grow (&obstack_for_string, c);
632   }
633   \\(.|\n)      {
634     char const *p = yytext + 1;
635     /* Quote only if escaping won't make the character visible.  */
636     if (isspace ((unsigned char) *p) && isprint ((unsigned char) *p))
637       p = quote (p);
638     else
639       p = quotearg_style_mem (escape_quoting_style, p, 1);
640     complain_at (*loc, _("invalid character after \\-escape: %s"), p);
641   }
644   /*--------------------------------------------.
645   | Scanning user-code characters and strings.  |
646   `--------------------------------------------*/
648 <SC_CHARACTER,SC_STRING>
650   {splice}|\\{splice}[^\n\[\]]  STRING_GROW;
653 <SC_CHARACTER>
655   "'"           STRING_GROW; BEGIN context_state;
656   \n            unexpected_newline (token_start, "'"); BEGIN context_state;
657   <<EOF>>       unexpected_eof (token_start, "'"); BEGIN context_state;
660 <SC_STRING>
662   "\""          STRING_GROW; BEGIN context_state;
663   \n            unexpected_newline (token_start, "\""); BEGIN context_state;
664   <<EOF>>       unexpected_eof (token_start, "\""); BEGIN context_state;
668   /*---------------------------------------------------.
669   | Strings, comments etc. can be found in user code.  |
670   `---------------------------------------------------*/
672 <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_PREDICATE>
674   "'" {
675     STRING_GROW;
676     context_state = YY_START;
677     token_start = loc->start;
678     BEGIN SC_CHARACTER;
679   }
680   "\"" {
681     STRING_GROW;
682     context_state = YY_START;
683     token_start = loc->start;
684     BEGIN SC_STRING;
685   }
686   "/"{splice}"*" {
687     STRING_GROW;
688     context_state = YY_START;
689     token_start = loc->start;
690     BEGIN SC_COMMENT;
691   }
692   "/"{splice}"/" {
693     STRING_GROW;
694     context_state = YY_START;
695     BEGIN SC_LINE_COMMENT;
696   }
701   /*-----------------------------------------------------------.
702   | Scanning some code in braces (actions, predicates). The    |
703   | initial "{" is already eaten.                              |
704   `-----------------------------------------------------------*/
706 <SC_BRACED_CODE,SC_PREDICATE>
708   "{"|"<"{splice}"%"  STRING_GROW; nesting++;
709   "%"{splice}">"      STRING_GROW; nesting--;
711   /* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
712      (as `<' `<%').  */
713   "<"{splice}"<"  STRING_GROW;
715   <<EOF>> {
716     int token = (YY_START == SC_BRACED_CODE) ? BRACED_CODE : BRACED_PREDICATE;
717     unexpected_eof (code_start, "}");
718     STRING_FINISH;
719     loc->start = code_start;
720     val->code = last_string;
721     BEGIN INITIAL;
722     return token;
723   }
726 <SC_BRACED_CODE>
728   "}" {
729     obstack_1grow (&obstack_for_string, '}');
731     --nesting;
732     if (nesting < 0)
733       {
734         STRING_FINISH;
735         loc->start = code_start;
736         val->code = last_string;
737         BEGIN INITIAL;
738         return BRACED_CODE;
739       }
740   }
743 <SC_PREDICATE>
745   "}" {
746     --nesting;
747     if (nesting < 0)
748       {
749         STRING_FINISH;
750         loc->start = code_start;
751         val->code = last_string;
752         BEGIN INITIAL;
753         return BRACED_PREDICATE;
754       }
755     else
756       obstack_1grow (&obstack_for_string, '}');
757   }
760   /*--------------------------------------------------------------.
761   | Scanning some prologue: from "%{" (already scanned) to "%}".  |
762   `--------------------------------------------------------------*/
764 <SC_PROLOGUE>
766   "%}" {
767     STRING_FINISH;
768     loc->start = code_start;
769     val->chars = last_string;
770     BEGIN INITIAL;
771     return PROLOGUE;
772   }
774   <<EOF>> {
775     unexpected_eof (code_start, "%}");
776     STRING_FINISH;
777     loc->start = code_start;
778     val->chars = last_string;
779     BEGIN INITIAL;
780     return PROLOGUE;
781   }
785   /*---------------------------------------------------------------.
786   | Scanning the epilogue (everything after the second "%%", which |
787   | has already been eaten).                                       |
788   `---------------------------------------------------------------*/
790 <SC_EPILOGUE>
792   <<EOF>> {
793     STRING_FINISH;
794     loc->start = code_start;
795     val->chars = last_string;
796     BEGIN INITIAL;
797     return EPILOGUE;
798   }
802   /*-----------------------------------------------------.
803   | By default, grow the string obstack with the input.  |
804   `-----------------------------------------------------*/
806 <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>. |
807   <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE>\n    STRING_GROW;
811 /* Read bytes from FP into buffer BUF of size SIZE.  Return the
812    number of bytes read.  Remove '\r' from input, treating \r\n
813    and isolated \r as \n.  */
815 static size_t
816 no_cr_read (FILE *fp, char *buf, size_t size)
818   size_t bytes_read = fread (buf, 1, size, fp);
819   if (bytes_read)
820     {
821       char *w = memchr (buf, '\r', bytes_read);
822       if (w)
823         {
824           char const *r = ++w;
825           char const *lim = buf + bytes_read;
827           for (;;)
828             {
829               /* Found an '\r'.  Treat it like '\n', but ignore any
830                  '\n' that immediately follows.  */
831               w[-1] = '\n';
832               if (r == lim)
833                 {
834                   int ch = getc (fp);
835                   if (ch != '\n' && ungetc (ch, fp) != ch)
836                     break;
837                 }
838               else if (*r == '\n')
839                 r++;
841               /* Copy until the next '\r'.  */
842               do
843                 {
844                   if (r == lim)
845                     return w - buf;
846                 }
847               while ((*w++ = *r++) != '\r');
848             }
850           return w - buf;
851         }
852     }
854   return bytes_read;
859 /*------------------------------------------------------.
860 | Scan NUMBER for a base-BASE integer at location LOC.  |
861 `------------------------------------------------------*/
863 static unsigned long int
864 scan_integer (char const *number, int base, location loc)
866   verify (INT_MAX < ULONG_MAX);
867   unsigned long int num = strtoul (number, NULL, base);
869   if (INT_MAX < num)
870     {
871       complain_at (loc, _("integer out of range: %s"), quote (number));
872       num = INT_MAX;
873     }
875   return num;
879 /*------------------------------------------------------------------.
880 | Convert universal character name UCN to a single-byte character,  |
881 | and return that character.  Return -1 if UCN does not correspond  |
882 | to a single-byte character.                                       |
883 `------------------------------------------------------------------*/
885 static int
886 convert_ucn_to_byte (char const *ucn)
888   verify (UCHAR_MAX <= INT_MAX);
889   unsigned long int code = strtoul (ucn + 2, NULL, 16);
891   /* FIXME: Currently we assume Unicode-compatible unibyte characters
892      on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes).  On
893      non-ASCII hosts we support only the portable C character set.
894      These limitations should be removed once we add support for
895      multibyte characters.  */
897   if (UCHAR_MAX < code)
898     return -1;
900 #if ! ('$' == 0x24 && '@' == 0x40 && '`' == 0x60 && '~' == 0x7e)
901   {
902     /* A non-ASCII host.  Use CODE to index into a table of the C
903        basic execution character set, which is guaranteed to exist on
904        all Standard C platforms.  This table also includes '$', '@',
905        and '`', which are not in the basic execution character set but
906        which are unibyte characters on all the platforms that we know
907        about.  */
908     static signed char const table[] =
909       {
910         '\0',   -1,   -1,   -1,   -1,   -1,   -1, '\a',
911         '\b', '\t', '\n', '\v', '\f', '\r',   -1,   -1,
912           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
913           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
914          ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
915          '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
916          '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
917          '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
918          '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',
919          'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
920          'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
921          'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_',
922          '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
923          'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
924          'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
925          'x',  'y',  'z',  '{',  '|',  '}',  '~'
926       };
928     code = code < sizeof table ? table[code] : -1;
929   }
930 #endif
932   return code;
936 /*----------------------------------------------------------------.
937 | Handle `#line INT "FILE"'.  ARGS has already skipped `#line '.  |
938 `----------------------------------------------------------------*/
940 static void
941 handle_syncline (char *args, location loc)
943   char *after_num;
944   unsigned long int lineno = strtoul (args, &after_num, 10);
945   char *file = strchr (after_num, '"') + 1;
946   *strchr (file, '"') = '\0';
947   if (INT_MAX <= lineno)
948     {
949       warn_at (loc, _("line number overflow"));
950       lineno = INT_MAX;
951     }
952   current_file = uniqstr_new (file);
953   boundary_set (&scanner_cursor, current_file, lineno, 1);
957 /*----------------------------------------------------------------.
958 | For a token or comment starting at START, report message MSGID, |
959 | which should say that an end marker was found before            |
960 | the expected TOKEN_END.                                         |
961 `----------------------------------------------------------------*/
963 static void
964 unexpected_end (boundary start, char const *msgid, char const *token_end)
966   location loc;
967   loc.start = start;
968   loc.end = scanner_cursor;
969   complain_at (loc, _(msgid), token_end);
973 /*------------------------------------------------------------------------.
974 | Report an unexpected EOF in a token or comment starting at START.       |
975 | An end of file was encountered and the expected TOKEN_END was missing.  |
976 `------------------------------------------------------------------------*/
978 static void
979 unexpected_eof (boundary start, char const *token_end)
981   unexpected_end (start, N_("missing `%s' at end of file"), token_end);
985 /*----------------------------------------.
986 | Likewise, but for unexpected newlines.  |
987 `----------------------------------------*/
989 static void
990 unexpected_newline (boundary start, char const *token_end)
992   unexpected_end (start, N_("missing `%s' at end of line"), token_end);
996 /*-------------------------.
997 | Initialize the scanner.  |
998 `-------------------------*/
1000 void
1001 gram_scanner_initialize (void)
1003   obstack_init (&obstack_for_string);
1007 /*-----------------------------------------------.
1008 | Free all the memory allocated to the scanner.  |
1009 `-----------------------------------------------*/
1011 void
1012 gram_scanner_free (void)
1014   obstack_free (&obstack_for_string, 0);
1015   /* Reclaim Flex's buffers.  */
1016   yylex_destroy ();