Update URLs to prefer https: to http:
[bison.git] / src / scan-gram.l
blob67748d882ff7744ea00c86ad626f43f3292a5fd7
1 /* Bison Grammar Scanner                             -*- C -*-
3    Copyright (C) 2002-2015, 2018-2021 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 <https://www.gnu.org/licenses/>.  */
20 %option debug nodefault noinput noyywrap never-interactive
21 %option prefix="gram_" outfile="lex.yy.c"
24 #include <c-ctype.h>
25 #include <errno.h>
26 #include <mbswidth.h>
27 #include <quote.h>
28 #include <quotearg.h>
30 #include "src/complain.h"
31 #include "src/files.h"
32 #include "src/getargs.h"
33 #include "src/gram.h"
34 #include "src/reader.h"
35 #include "src/scan-gram.h"
36 #include "src/uniqstr.h"
38 #define FLEX_PREFIX(Id) gram_ ## Id
39 #include "src/flex-scanner.h"
41 /* Work around a bug in flex 2.5.31.  See Debian bug 333231
42    <https://bugs.debian.org/333231>.  */
43 #undef gram_wrap
44 #define gram_wrap() 1
46 #define YY_DECL GRAM_LEX_DECL
48 /* Location of scanner cursor.  */
49 static boundary scanner_cursor;
51 #define YY_USER_ACTION  location_compute (loc, &scanner_cursor, yytext, yyleng);
53 /* Report that yytext is an extension, and evaluate to its token kind.  */
54 #define BISON_DIRECTIVE(Directive)                              \
55   (bison_directive (loc, yytext), PERCENT_ ## Directive)
57 #define RETURN_PERCENT_PARAM(Value)             \
58   RETURN_VALUE(PERCENT_PARAM, param_ ## Value)
60 #define RETURN_PERCENT_FLAG(Value)                      \
61   RETURN_VALUE(PERCENT_FLAG, uniqstr_new (Value))
63 #define RETURN_VALUE(Token, Value)              \
64   do {                                          \
65     val->Token = Value;                         \
66     return Token;                               \
67   } while (0)
69 #define ROLLBACK_CURRENT_TOKEN                                  \
70   do {                                                          \
71     scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);     \
72     scanner_cursor.byte -= yyleng;                              \
73     yyless (0);                                                 \
74   } while (0)
76 #define DEPRECATED_DIRECTIVE(Msg)                               \
77   do {                                                          \
78     deprecated_directive (loc, yytext, Msg);                    \
79     scanner_cursor.column -= mbsnwidth (Msg, strlen (Msg), 0);  \
80     scanner_cursor.byte -= strlen (Msg);                        \
81     for (size_t i = strlen (Msg); i != 0; --i)                  \
82       unput (Msg[i - 1]);                                       \
83   } while (0)
86 #define STRING_GROW_ESCAPE(Char)                                \
87   do {                                                          \
88     verify (UCHAR_MAX < ULONG_MAX);                             \
89     long c = Char;                                              \
90     bool valid = 0 < c && c <= UCHAR_MAX;                       \
91     if (!valid)                                                 \
92       complain (loc, complaint,                                 \
93                 _("invalid number after \\-escape: %s"),        \
94                 yytext + 1);                                    \
95     if (YY_START == SC_ESCAPED_CHARACTER)                       \
96       STRING_1GROW (valid ? c : '?');                           \
97     else                                                        \
98       STRING_GROW ();                                           \
99   } while (0)
102 /* The current file name.  Might change with #line.  */
103 static uniqstr current_file = NULL;
105 /* A string representing the most recently saved token.  */
106 static char *last_string = NULL;
108 /* Bracketed identifier. */
109 static uniqstr bracketed_id_str = NULL;
110 static location bracketed_id_loc;
111 static boundary bracketed_id_start;
112 static int bracketed_id_context_state = 0;
114 void
115 gram_scanner_last_string_free (void)
117   STRING_FREE ();
120 static void handle_syncline (char *, location);
121 static int scan_integer (char const *p, int base, location loc);
122 static int convert_ucn_to_byte (char const *hex_text);
123 static void unexpected_eof (boundary, char const *);
124 static void unexpected_newline (boundary, char const *);
127  /* A C-like comment in directives/rules. */
128 %x SC_YACC_COMMENT
129  /* Characters and strings in directives/rules. */
130 %x SC_ESCAPED_CHARACTER SC_ESCAPED_STRING SC_ESCAPED_TSTRING
131  /* A identifier was just read in directives/rules.  Special state
132     to capture the sequence 'identifier :'. */
133 %x SC_AFTER_IDENTIFIER
135  /* POSIX says that a tag must be both an id and a C union member, but
136     historically almost any character is allowed in a tag.  We
137     disallow NUL, as this simplifies our implementation.  We match
138     angle brackets in nested pairs: several languages use them for
139     generics/template types.  */
140 %x SC_TAG
142  /* Four types of user code:
143     - prologue (code between '%{' '%}' in the first section, before %%);
144     - actions, printers, union, etc, (between braced in the middle section);
145     - epilogue (everything after the second %%).
146     - predicate (code between '%?{' and '{' in middle section); */
147 %x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE SC_PREDICATE
148  /* C and C++ comments in code. */
149 %x SC_COMMENT SC_LINE_COMMENT
150  /* Strings and characters in code. */
151 %x SC_STRING SC_CHARACTER
152  /* Bracketed identifiers support. */
153 %x SC_BRACKETED_ID SC_RETURN_BRACKETED_ID
155 letter    [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
156 id        {letter}({letter}|[-0-9])*
157 int       [0-9]+
158 xint      0[xX][0-9abcdefABCDEF]+
160 eol       \n|\r\n
162  /* UTF-8 Encoded Unicode Code Point, from Flex's documentation. */
163 mbchar    [\x09\x0A\x0D\x20-\x7E]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF]([\x80-\xBF]{2})|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x\90-\xBF]([\x80-\xBF]{2})|[\xF1-\xF3]([\x80-\xBF]{3})|\xF4[\x80-\x8F]([\x80-\xBF]{2})
165 /* Zero or more instances of backslash-newline.  Following GCC, allow
166    white space between the backslash and the newline.  */
167 splice   (\\[ \f\t\v]*{eol})*
169 /* An equal sign, with optional leading whitespaces. This is used in some
170    deprecated constructs. */
171 sp       [[:space:]]*
172 eqopt    ({sp}=)?
176   /* Nesting level.  Either for nested braces, or nested angle brackets
177      (but not mixed).  */
178   int nesting PACIFY_CC (= 0);
180   /* Parent context state, when applicable.  */
181   int context_state PACIFY_CC (= 0);
183   /* Location of most recent identifier, when applicable.  */
184   location id_loc PACIFY_CC (= empty_loc);
186   /* Where containing code started, when applicable.  Its initial
187      value is relevant only when yylex is invoked in the SC_EPILOGUE
188      start condition.  */
189   boundary code_start = scanner_cursor;
191   /* Where containing comment or string or character literal started,
192      when applicable.  */
193   boundary token_start PACIFY_CC (= scanner_cursor);
195   /* We cannot trust YY_USER_INIT, whose semantics changes over time
196      (it moved in Flex 2.5.38).  */
197   static bool first = true;
198   if (first)
199     {
200       scanner_cursor = loc->start;
201       first = false;
202     }
206   /*-----------------------.
207   | Scanning white space.  |
208   `-----------------------*/
210 <INITIAL,SC_AFTER_IDENTIFIER,SC_BRACKETED_ID,SC_RETURN_BRACKETED_ID>
212   /* Comments and white space.  */
213   "," {
214      complain (loc, Wother, _("stray ',' treated as white space"));
215   }
216   [ \f\t\v\r]|{eol}  |
217   "//".*       continue;
218   "/*" {
219     token_start = loc->start;
220     context_state = YY_START;
221     BEGIN SC_YACC_COMMENT;
222   }
224   ^"#line "{int}(" \"".*"\"")?{eol} {
225     handle_syncline (yytext + sizeof "#line " - 1, *loc);
226   }
230   /*----------------------------.
231   | Scanning Bison directives.  |
232   `----------------------------*/
234   /* For directives that are also command line options, the regex must be
235         "%..."
236      after "[-_]"s are removed, and the directive must match the --long
237      option name, with a single string argument.  Otherwise, add exceptions
238      to ../build-aux/cross-options.pl.  */
240 <INITIAL>
242   "%binary"                         return BISON_DIRECTIVE (NONASSOC);
243   "%code"                           return BISON_DIRECTIVE (CODE);
244   "%debug"                          RETURN_PERCENT_FLAG ("parse.trace");
245   "%default-prec"                   return BISON_DIRECTIVE (DEFAULT_PREC);
246   "%define"                         return BISON_DIRECTIVE (DEFINE);
247   "%defines"                        return BISON_DIRECTIVE (DEFINES);
248   "%destructor"                     return BISON_DIRECTIVE (DESTRUCTOR);
249   "%dprec"                          return BISON_DIRECTIVE (DPREC);
250   "%empty"                          return BISON_DIRECTIVE (EMPTY);
251   "%expect"                         return BISON_DIRECTIVE (EXPECT);
252   "%expect-rr"                      return BISON_DIRECTIVE (EXPECT_RR);
253   "%file-prefix"                    RETURN_VALUE (PERCENT_FILE_PREFIX, uniqstr_new (yytext));
254   "%initial-action"                 return BISON_DIRECTIVE (INITIAL_ACTION);
255   "%glr-parser"                     return BISON_DIRECTIVE (GLR_PARSER);
256   "%language"                       return BISON_DIRECTIVE (LANGUAGE);
257   "%left"                           return PERCENT_LEFT;
258   "%lex-param"                      RETURN_PERCENT_PARAM (lex);
259   "%locations"                      RETURN_PERCENT_FLAG ("locations");
260   "%merge"                          return BISON_DIRECTIVE (MERGE);
261   "%no-default-prec"                return BISON_DIRECTIVE (NO_DEFAULT_PREC);
262   "%no-lines"                       return BISON_DIRECTIVE (NO_LINES);
263   "%nonassoc"                       return PERCENT_NONASSOC;
264   "%nondeterministic-parser"        return BISON_DIRECTIVE (NONDETERMINISTIC_PARSER);
265   "%nterm"                          return BISON_DIRECTIVE (NTERM);
266   "%output"                         return BISON_DIRECTIVE (OUTPUT);
267   "%param"                          RETURN_PERCENT_PARAM (both);
268   "%parse-param"                    RETURN_PERCENT_PARAM (parse);
269   "%prec"                           return PERCENT_PREC;
270   "%precedence"                     return BISON_DIRECTIVE (PRECEDENCE);
271   "%printer"                        return BISON_DIRECTIVE (PRINTER);
272   "%require"                        return BISON_DIRECTIVE (REQUIRE);
273   "%right"                          return PERCENT_RIGHT;
274   "%skeleton"                       return BISON_DIRECTIVE (SKELETON);
275   "%start"                          return PERCENT_START;
276   "%term"                           return BISON_DIRECTIVE (TOKEN);
277   "%token"                          return PERCENT_TOKEN;
278   "%token-table"                    return BISON_DIRECTIVE (TOKEN_TABLE);
279   "%type"                           return PERCENT_TYPE;
280   "%union"                          return PERCENT_UNION;
281   "%verbose"                        return BISON_DIRECTIVE (VERBOSE);
282   "%yacc"                           return PERCENT_YACC;
284   /* Deprecated since Bison 2.3b (2008-05-27), but the warning is
285      issued only since Bison 3.4. */
286   "%pure"[-_]"parser"               RETURN_VALUE (PERCENT_PURE_PARSER, uniqstr_new (yytext));
288   /* Deprecated since Bison 3.0 (2013-07-25), but the warning is
289      issued only since Bison 3.3. */
290   "%error-verbose"                  RETURN_VALUE (PERCENT_ERROR_VERBOSE, uniqstr_new (yytext));
292   /* Deprecated since Bison 2.6 (2012-07-19), but the warning is
293      issued only since Bison 3.3. */
294   "%name"[-_]"prefix"{eqopt}{sp}    RETURN_VALUE (PERCENT_NAME_PREFIX, uniqstr_new (yytext));
296   /* Deprecated since Bison 2.7.90, 2012. */
297   "%default"[-_]"prec"              DEPRECATED_DIRECTIVE ("%default-prec");
298   "%error"[-_]"verbose"             RETURN_VALUE (PERCENT_ERROR_VERBOSE, uniqstr_new (yytext));
299   "%expect"[-_]"rr"                 DEPRECATED_DIRECTIVE ("%expect-rr");
300   "%file-prefix"{eqopt}             RETURN_VALUE (PERCENT_FILE_PREFIX, uniqstr_new (yytext));
301   "%fixed"[-_]"output"[-_]"files"   DEPRECATED_DIRECTIVE ("%output \"y.tab.c\"");
302   "%no"[-_]"default"[-_]"prec"      DEPRECATED_DIRECTIVE ("%no-default-prec");
303   "%no"[-_]"lines"                  DEPRECATED_DIRECTIVE ("%no-lines");
304   "%output"{eqopt}                  DEPRECATED_DIRECTIVE ("%output");
305   "%token"[-_]"table"               DEPRECATED_DIRECTIVE ("%token-table");
307   "%"{id} {
308     complain (loc, complaint, _("invalid directive: %s"), quote (yytext));
309     return GRAM_error;
310   }
312   ":"                     return COLON;
313   "="                     return EQUAL;
314   "|"                     return PIPE;
315   ";"                     return SEMICOLON;
317   {id} {
318     val->ID = uniqstr_new (yytext);
319     id_loc = *loc;
320     bracketed_id_str = NULL;
321     BEGIN SC_AFTER_IDENTIFIER;
322   }
324   {int}      RETURN_VALUE (INT_LITERAL, scan_integer (yytext, 10, *loc));
325   {xint}     RETURN_VALUE (INT_LITERAL, scan_integer (yytext, 16, *loc));
327   /* Identifiers may not start with a digit.  Yet, don't silently
328      accept "1FOO" as "1 FOO".  */
329   {int}{id} {
330     complain (loc, complaint, _("invalid identifier: %s"), quote (yytext));
331     return GRAM_error;
332   }
334   /* Characters.  */
335   "'"         token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
337   /* Strings. */
338   "\""        token_start = loc->start; STRING_1GROW ('"'); BEGIN SC_ESCAPED_STRING;
339   "_(\""      token_start = loc->start; STRING_1GROW ('"'); BEGIN SC_ESCAPED_TSTRING;
341   /* Prologue. */
342   "%{"        code_start = loc->start; BEGIN SC_PROLOGUE;
344   /* Code in between braces.  */
345   "{" {
346     STRING_GROW ();
347     nesting = 0;
348     code_start = loc->start;
349     BEGIN SC_BRACED_CODE;
350   }
352   /* Semantic predicate. */
353   "%?"([ \f\t\v]|{eol})*"{" {
354     nesting = 0;
355     code_start = loc->start;
356     BEGIN SC_PREDICATE;
357   }
359   /* A type. */
360   "<*>"       return TAG_ANY;
361   "<>"        return TAG_NONE;
362   "<"         {
363     nesting = 0;
364     token_start = loc->start;
365     BEGIN SC_TAG;
366   }
368   "%%" {
369     static int percent_percent_count;
370     if (++percent_percent_count == 2)
371       BEGIN SC_EPILOGUE;
372     return PERCENT_PERCENT;
373   }
375   "[" {
376     bracketed_id_str = NULL;
377     bracketed_id_start = loc->start;
378     bracketed_id_context_state = YY_START;
379     BEGIN SC_BRACKETED_ID;
380   }
382   [^\[%A-Za-z0-9_<>{}""''*;|=/, \f\r\n\t\v]+|. {
383     complain (loc, complaint, "%s: %s",
384               ngettext ("invalid character", "invalid characters", yyleng),
385               quote_mem (yytext, yyleng));
386     return GRAM_error;
387   }
389   <<EOF>> {
390     loc->start = loc->end = scanner_cursor;
391     yyterminate ();
392   }
396   /*--------------------------------------------------------------.
397   | Supporting \0 complexifies our implementation for no expected |
398   | added value.                                                  |
399   `--------------------------------------------------------------*/
401 <SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_TSTRING,SC_TAG>
403   \0         {
404     complain (loc, complaint, _("invalid null character"));
405     STRING_FINISH ();
406     STRING_FREE ();
407     return GRAM_error;
408   }
412   /*-----------------------------------------------------------------.
413   | Scanning after an identifier, checking whether a colon is next.  |
414   `-----------------------------------------------------------------*/
416 <SC_AFTER_IDENTIFIER>
418   "[" {
419     if (bracketed_id_str)
420       {
421         ROLLBACK_CURRENT_TOKEN;
422         BEGIN SC_RETURN_BRACKETED_ID;
423         *loc = id_loc;
424         return ID;
425       }
426     else
427       {
428         bracketed_id_start = loc->start;
429         bracketed_id_context_state = YY_START;
430         BEGIN SC_BRACKETED_ID;
431       }
432   }
433   ":" {
434     ROLLBACK_CURRENT_TOKEN;
435     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
436     *loc = id_loc;
437     return ID_COLON;
438   }
439   . {
440     ROLLBACK_CURRENT_TOKEN;
441     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
442     *loc = id_loc;
443     return ID;
444   }
445   <<EOF>> {
446     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
447     *loc = id_loc;
448     return ID;
449   }
452   /*--------------------------------.
453   | Scanning bracketed identifiers. |
454   `--------------------------------*/
456 <SC_BRACKETED_ID>
458   {id} {
459     if (bracketed_id_str)
460       {
461         complain (loc, complaint,
462                   _("unexpected identifier in bracketed name: %s"),
463                   quote (yytext));
464         return GRAM_error;
465       }
466     else
467       {
468         bracketed_id_str = uniqstr_new (yytext);
469         bracketed_id_loc = *loc;
470       }
471   }
472   "]" {
473     BEGIN bracketed_id_context_state;
474     if (bracketed_id_str)
475       {
476         if (INITIAL == bracketed_id_context_state)
477           {
478             val->BRACKETED_ID = bracketed_id_str;
479             bracketed_id_str = 0;
480             *loc = bracketed_id_loc;
481             return BRACKETED_ID;
482           }
483       }
484     else
485       {
486         complain (loc, complaint, _("an identifier expected"));
487         return GRAM_error;
488       }
489   }
491   [^\].A-Za-z0-9_/ \f\r\n\t\v]+|. {
492     complain (loc, complaint, "%s: %s",
493               ngettext ("invalid character in bracketed name",
494                         "invalid characters in bracketed name", yyleng),
495               quote_mem (yytext, yyleng));
496     return GRAM_error;
497   }
499   <<EOF>> {
500     BEGIN bracketed_id_context_state;
501     unexpected_eof (bracketed_id_start, "]");
502   }
505 <SC_RETURN_BRACKETED_ID>
507   . {
508     ROLLBACK_CURRENT_TOKEN;
509     val->BRACKETED_ID = bracketed_id_str;
510     bracketed_id_str = 0;
511     *loc = bracketed_id_loc;
512     BEGIN INITIAL;
513     return BRACKETED_ID;
514   }
518   /*---------------------------------------------------------------.
519   | Scanning a Yacc comment.  The initial '/ *' is already eaten.  |
520   `---------------------------------------------------------------*/
522 <SC_YACC_COMMENT>
524   "*/"     BEGIN context_state;
525   .|{eol}  continue;
526   <<EOF>>  unexpected_eof (token_start, "*/"); BEGIN context_state;
530   /*------------------------------------------------------------.
531   | Scanning a C comment.  The initial '/ *' is already eaten.  |
532   `------------------------------------------------------------*/
534 <SC_COMMENT>
536   "*"{splice}"/"  STRING_GROW (); BEGIN context_state;
537   <<EOF>>         unexpected_eof (token_start, "*/"); BEGIN context_state;
541   /*--------------------------------------------------------------.
542   | Scanning a line comment.  The initial '//' is already eaten.  |
543   `--------------------------------------------------------------*/
545 <SC_LINE_COMMENT>
547   {eol}          STRING_GROW (); BEGIN context_state;
548   {splice}       STRING_GROW ();
549   <<EOF>>        BEGIN context_state;
553   /*------------------------------------------------.
554   | Scanning a Bison string, including its escapes. |
555   | The initial quote is already eaten.             |
556   `------------------------------------------------*/
558 <SC_ESCAPED_STRING>
560   "\"" {
561     STRING_1GROW ('"');
562     STRING_FINISH ();
563     BEGIN INITIAL;
564     loc->start = token_start;
565     complain (loc, Wyacc,
566               _("POSIX Yacc does not support string literals"));
567     RETURN_VALUE (STRING, last_string);
568   }
569   <<EOF>>   unexpected_eof (token_start, "\"");
570   "\n"      unexpected_newline (token_start, "\"");
573 <SC_ESCAPED_TSTRING>
575   "\")" {
576     STRING_1GROW ('"');
577     STRING_FINISH ();
578     BEGIN INITIAL;
579     loc->start = token_start;
580     complain (loc, Wyacc,
581               _("POSIX Yacc does not support string literals"));
582     RETURN_VALUE (TSTRING, last_string);
583   }
584   <<EOF>>   unexpected_eof (token_start, "\")");
585   "\n"      unexpected_newline (token_start, "\")");
590   /*----------------------------------------------------------.
591   | Scanning a Bison character literal, decoding its escapes. |
592   | The initial quote is already eaten.                       |
593   `----------------------------------------------------------*/
595 <SC_ESCAPED_CHARACTER>
597   "'" {
598     STRING_FINISH ();
599     BEGIN INITIAL;
600     loc->start = token_start;
602     if (last_string[0] == '\0')
603       {
604         complain (loc, complaint, _("empty character literal"));
605         STRING_FREE ();
606         return GRAM_error;
607       }
608     else if (last_string[1] != '\0')
609       {
610         complain (loc, complaint, _("extra characters in character literal"));
611         STRING_FREE ();
612         return GRAM_error;
613       }
614     else
615       {
616         val->CHAR_LITERAL = last_string[0];
617         STRING_FREE ();
618         return CHAR_LITERAL;
619       }
620   }
621   {eol}     unexpected_newline (token_start, "'");
622   <<EOF>>   unexpected_eof (token_start, "'");
627   /*--------------------------------------------------------------.
628   | Scanning a tag.  The initial angle bracket is already eaten.  |
629   `--------------------------------------------------------------*/
631 <SC_TAG>
633   ">" {
634     --nesting;
635     if (nesting < 0)
636       {
637         STRING_FINISH ();
638         loc->start = token_start;
639         val->TAG = uniqstr_new (last_string);
640         STRING_FREE ();
641         BEGIN INITIAL;
642         return TAG;
643       }
644     STRING_GROW ();
645   }
647   ([^<>]|->)+ STRING_GROW ();
648   "<"+   STRING_GROW (); nesting += yyleng;
650   <<EOF>>   unexpected_eof (token_start, ">");
653   /*----------------------------.
654   | Decode escaped characters.  |
655   `----------------------------*/
657 <SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_TSTRING>
659   \\[0-7]{1,3} {
660     STRING_GROW_ESCAPE (strtol (yytext + 1, NULL, 8));
661   }
663   \\x[0-9abcdefABCDEF]+ {
664     STRING_GROW_ESCAPE (strtol (yytext + 2, NULL, 16));
665   }
667   \\a   STRING_GROW_ESCAPE ('\a');
668   \\b   STRING_GROW_ESCAPE ('\b');
669   \\f   STRING_GROW_ESCAPE ('\f');
670   \\n   STRING_GROW_ESCAPE ('\n');
671   \\r   STRING_GROW_ESCAPE ('\r');
672   \\t   STRING_GROW_ESCAPE ('\t');
673   \\v   STRING_GROW_ESCAPE ('\v');
675   /* \\[\"\'?\\] would be shorter, but it confuses xgettext.  */
676   \\("\""|"'"|"?"|"\\")  STRING_GROW_ESCAPE (yytext[1]);
678   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
679     STRING_GROW_ESCAPE (convert_ucn_to_byte (yytext));
680   }
682   \\(.|{eol})      {
683     char const *p = yytext + 1;
684     /* Quote only if escaping won't make the character visible.  */
685     if (c_isspace ((unsigned char) *p) && c_isprint ((unsigned char) *p))
686       p = quote (p);
687     else
688       p = quotearg_style_mem (escape_quoting_style, p, 1);
689     complain (loc, complaint, _("invalid character after \\-escape: %s"),
690               p);
691     STRING_1GROW ('?');
692   }
694   "\\"             {
695     // None of the other rules matched: the last character of this
696     // file is "\".  But Flex does not support "\\<<EOF>>".
697     unexpected_eof (token_start,
698                     YY_START == SC_ESCAPED_CHARACTER ? "?'"
699                     : YY_START == SC_ESCAPED_STRING ? "?\""
700                     : "?\")");
701   }
704   /*--------------------------------------------.
705   | Scanning user-code characters and strings.  |
706   `--------------------------------------------*/
708 <SC_CHARACTER,SC_STRING>
710   {splice}|\\{splice}[^\n\[\]]  STRING_GROW ();
713 <SC_CHARACTER>
715   "'"           STRING_GROW (); BEGIN context_state;
716   {eol}         unexpected_newline (token_start, "'");
717   <<EOF>>       unexpected_eof (token_start, "'");
720 <SC_STRING>
722   "\""          STRING_GROW (); BEGIN context_state;
723   {eol}         unexpected_newline (token_start, "\"");
724   <<EOF>>       unexpected_eof (token_start, "\"");
728   /*---------------------------------------------------.
729   | Strings, comments etc. can be found in user code.  |
730   `---------------------------------------------------*/
732 <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_PREDICATE>
734   "'" {
735     STRING_GROW ();
736     context_state = YY_START;
737     token_start = loc->start;
738     BEGIN SC_CHARACTER;
739   }
740   "\"" {
741     STRING_GROW ();
742     context_state = YY_START;
743     token_start = loc->start;
744     BEGIN SC_STRING;
745   }
746   "/"{splice}"*" {
747     STRING_GROW ();
748     context_state = YY_START;
749     token_start = loc->start;
750     BEGIN SC_COMMENT;
751   }
752   "/"{splice}"/" {
753     STRING_GROW ();
754     context_state = YY_START;
755     BEGIN SC_LINE_COMMENT;
756   }
761   /*-----------------------------------------------------------.
762   | Scanning some code in braces (actions, predicates). The    |
763   | initial "{" is already eaten.                              |
764   `-----------------------------------------------------------*/
766 <SC_BRACED_CODE,SC_PREDICATE>
768   "{"|"<"{splice}"%"  STRING_GROW (); nesting++;
769   "%"{splice}">"      STRING_GROW (); nesting--;
771   /* Tokenize '<<%' correctly (as '<<' '%') rather than incorrectly
772      (as '<' '<%').  */
773   "<"{splice}"<"  STRING_GROW ();
775   <<EOF>>   unexpected_eof (code_start, "}");
778 <SC_BRACED_CODE>
780   "}" {
781     STRING_1GROW ('}');
783     --nesting;
784     if (nesting < 0)
785       {
786         STRING_FINISH ();
787         loc->start = code_start;
788         BEGIN INITIAL;
789         RETURN_VALUE (BRACED_CODE, last_string);
790       }
791   }
794 <SC_PREDICATE>
796   "}" {
797     --nesting;
798     if (nesting < 0)
799       {
800         STRING_FINISH ();
801         loc->start = code_start;
802         BEGIN INITIAL;
803         RETURN_VALUE (BRACED_PREDICATE, last_string);
804       }
805     else
806       STRING_1GROW ('}');
807   }
810   /*--------------------------------------------------------------.
811   | Scanning some prologue: from "%{" (already scanned) to "%}".  |
812   `--------------------------------------------------------------*/
814 <SC_PROLOGUE>
816   "%}" {
817     STRING_FINISH ();
818     loc->start = code_start;
819     BEGIN INITIAL;
820     RETURN_VALUE (PROLOGUE, last_string);
821   }
823   <<EOF>>   unexpected_eof (code_start, "%}");
827   /*---------------------------------------------------------------.
828   | Scanning the epilogue (everything after the second "%%", which |
829   | has already been eaten).                                       |
830   `---------------------------------------------------------------*/
832 <SC_EPILOGUE>
834   <<EOF>> {
835     STRING_FINISH ();
836     loc->start = code_start;
837     BEGIN INITIAL;
838     RETURN_VALUE (EPILOGUE, last_string);
839   }
843   /*-----------------------------------------------------.
844   | By default, grow the string obstack with the input.  |
845   `-----------------------------------------------------*/
847 <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_TSTRING>
849   /* Accept multibyte characters in one block instead of byte after
850      byte, so that add_column_width and mbsnwidth can compute correct
851      screen width.
853      Add a fallthrough "|." so that non UTF-8 input is still accepted
854      and does not jam the scanner.  */
855   {mbchar}|.   STRING_GROW ();
861 /*------------------------------------------------------.
862 | Scan NUMBER for a base-BASE integer at location LOC.  |
863 `------------------------------------------------------*/
865 static int
866 scan_integer (char const *number, int base, location loc)
868   verify (INT_MAX < ULONG_MAX);
869   if (base == 16)
870     complain (&loc, Wyacc,
871               _("POSIX Yacc does not support hexadecimal literals"));
873   errno = 0;
874   long num = strtol (number, NULL, base);
876   if (! (0 <= num && num <= INT_MAX && errno == 0))
877     {
878       complain (&loc, complaint, _("integer out of range: %s"),
879                 quote (number));
880       num = INT_MAX;
881     }
883   return num;
887 /*------------------------------------------------------------------.
888 | Convert universal character name UCN to a single-byte character,  |
889 | and return that character.  Return -1 if UCN does not correspond  |
890 | to a single-byte character.                                       |
891 `------------------------------------------------------------------*/
893 static int
894 convert_ucn_to_byte (char const *ucn)
896   verify (UCHAR_MAX <= INT_MAX);
897   long code = strtol (ucn + 2, NULL, 16);
899   /* FIXME: Currently we assume Unicode-compatible unibyte characters
900      on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes).  On
901      non-ASCII hosts we support only the portable C character set.
902      These limitations should be removed once we add support for
903      multibyte characters.  */
905   if (! (0 <= code && code <= UCHAR_MAX))
906     return -1;
908 #if ! ('$' == 0x24 && '@' == 0x40 && '`' == 0x60 && '~' == 0x7e)
909   {
910     /* A non-ASCII host.  Use CODE to index into a table of the C
911        basic execution character set, which is guaranteed to exist on
912        all Standard C platforms.  This table also includes '$', '@',
913        and '`', which are not in the basic execution character set but
914        which are unibyte characters on all the platforms that we know
915        about.  */
916     static signed char const table[] =
917       {
918         '\0',   -1,   -1,   -1,   -1,   -1,   -1, '\a',
919         '\b', '\t', '\n', '\v', '\f', '\r',   -1,   -1,
920           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
921           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
922          ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
923          '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
924          '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
925          '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
926          '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',
927          'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
928          'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
929          'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_',
930          '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
931          'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
932          'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
933          'x',  'y',  'z',  '{',  '|',  '}',  '~'
934       };
936     code = code < sizeof table ? table[code] : -1;
937   }
938 #endif
940   return code;
944 /*----------------------------------------------------------------------------.
945 | Handle '#line INT_LITERAL( "FILE")?\n'.  ARGS has already skipped '#line '. |
946 `----------------------------------------------------------------------------*/
948 static void
949 handle_syncline (char *args, location loc)
951   char *file;
952   errno = 0;
953   long lineno = strtol (args, &file, 10);
954   if (! (0 <= lineno && lineno <= INT_MAX && errno == 0))
955     {
956       complain (&loc, Wother, _("line number overflow"));
957       lineno = INT_MAX;
958     }
960   file = strchr (file, '"');
961   if (file)
962     {
963       *strchr (file + 1, '"') = '\0';
964       current_file = uniqstr_new (file + 1);
965     }
966   boundary_set (&scanner_cursor, current_file, lineno, 1, 1);
970 /*----------------------------------------------------------------.
971 | For a token or comment starting at START, report message MSGID, |
972 | which should say that an end marker was found before the        |
973 | expected TOKEN_END. Then, pretend that TOKEN_END was found.     |
974 `----------------------------------------------------------------*/
976 static void
977 unexpected_end (boundary start, char const *msgid, char const *token_end)
979   location loc;
980   loc.start = start;
981   loc.end = scanner_cursor;
982   size_t i = strlen (token_end);
984   /* Adjust scanner cursor so that any later message does not count
985      the characters about to be inserted.  */
986   scanner_cursor.column -= i;
987   scanner_cursor.byte -= i;
989   while (i != 0)
990     unput (token_end[--i]);
992   token_end = quote (token_end);
993   /* Instead of '\'', display "'".  */
994   if (STREQ (token_end, "'\\''"))
995     token_end = "\"'\"";
996   complain (&loc, complaint, msgid, token_end);
1000 /*------------------------------------------------------------------------.
1001 | Report an unexpected EOF in a token or comment starting at START.       |
1002 | An end of file was encountered and the expected TOKEN_END was missing.  |
1003 | After reporting the problem, pretend that TOKEN_END was found.          |
1004 `------------------------------------------------------------------------*/
1006 static void
1007 unexpected_eof (boundary start, char const *token_end)
1009   unexpected_end (start, _("missing %s at end of file"), token_end);
1013 /*----------------------------------------.
1014 | Likewise, but for unexpected newlines.  |
1015 `----------------------------------------*/
1017 static void
1018 unexpected_newline (boundary start, char const *token_end)
1020   unexpected_end (start, _("missing %s at end of line"), token_end);
1024 void
1025 gram_scanner_open (const char *gram)
1027   gram__flex_debug = trace_flag & trace_scan;
1028   gram_debug = trace_flag & trace_parse;
1029   obstack_init (&obstack_for_string);
1030   current_file = gram;
1031   gram_in = xfopen (gram, "r");
1035 void
1036 gram_scanner_close (void)
1038   xfclose (gram_in);
1039   /* Reclaim Flex's buffers.  */
1040   yylex_destroy ();
1044 void
1045 gram_scanner_free (void)
1047   obstack_free (&obstack_for_string, 0);