1 /* Bison Grammar Scanner                             -*- C -*-
 
   3    Copyright (C) 2002-2012 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>.  */
 
  29 #define FLEX_PREFIX(Id) gram_ ## Id
 
  30 #include "flex-scanner.h"
 
  43 #include "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 ROLLBACK_CURRENT_TOKEN                                  \
 
  60     scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);     \
 
  64 /* A string representing the most recently saved token.  */
 
  65 static char *last_string;
 
  67 /* Bracketed identifier. */
 
  68 static uniqstr bracketed_id_str = 0;
 
  69 static location bracketed_id_loc;
 
  70 static boundary bracketed_id_start;
 
  71 static int bracketed_id_context_state = 0;
 
  74 gram_scanner_last_string_free (void)
 
  79 static void handle_syncline (char *, location);
 
  80 static unsigned long int scan_integer (char const *p, int base, location loc);
 
  81 static int convert_ucn_to_byte (char const *hex_text);
 
  82 static void unexpected_eof (boundary, char const *);
 
  83 static void unexpected_newline (boundary, char const *);
 
  86  /* A C-like comment in directives/rules. */
 
  88  /* Strings and characters in directives/rules. */
 
  89 %x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
 
  90  /* A identifier was just read in directives/rules.  Special state
 
  91     to capture the sequence `identifier :'. */
 
  92 %x SC_AFTER_IDENTIFIER
 
  94  /* Three types of user code:
 
  95     - prologue (code between `%{' `%}' in the first section, before %%);
 
  96     - actions, printers, union, etc, (between braced in the middle section);
 
  97     - epilogue (everything after the second %%). */
 
  98 %x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE
 
  99  /* C and C++ comments in code. */
 
 100 %x SC_COMMENT SC_LINE_COMMENT
 
 101  /* Strings and characters in code. */
 
 102 %x SC_STRING SC_CHARACTER
 
 103  /* Bracketed identifiers support. */
 
 104 %x SC_BRACKETED_ID SC_RETURN_BRACKETED_ID
 
 106 letter    [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
 
 107 id        {letter}({letter}|[-0-9])*
 
 111 /* POSIX says that a tag must be both an id and a C union member, but
 
 112    historically almost any character is allowed in a tag.  We disallow
 
 113    NUL and newline, as this simplifies our implementation.  */
 
 116 /* Zero or more instances of backslash-newline.  Following GCC, allow
 
 117    white space between the backslash and the newline.  */
 
 118 splice   (\\[ \f\t\v]*\n)*
 
 122   /* Nesting level of the current code in braces.  */
 
 123   int braces_level PACIFY_CC (= 0);
 
 125   /* Parent context state, when applicable.  */
 
 126   int context_state PACIFY_CC (= 0);
 
 128   /* Location of most recent identifier, when applicable.  */
 
 129   location id_loc PACIFY_CC (= empty_location);
 
 131   /* Where containing code started, when applicable.  Its initial
 
 132      value is relevant only when yylex is invoked in the SC_EPILOGUE
 
 134   boundary code_start = scanner_cursor;
 
 136   /* Where containing comment or string or character literal started,
 
 138   boundary token_start PACIFY_CC (= scanner_cursor);
 
 142   /*-----------------------.
 
 143   | Scanning white space.  |
 
 144   `-----------------------*/
 
 146 <INITIAL,SC_AFTER_IDENTIFIER,SC_BRACKETED_ID,SC_RETURN_BRACKETED_ID>
 
 148   /* Comments and white space.  */
 
 149   ","          warn_at (*loc, _("stray `,' treated as white space"));
 
 153     token_start = loc->start;
 
 154     context_state = YY_START;
 
 155     BEGIN SC_YACC_COMMENT;
 
 158   /* #line directives are not documented, and may be withdrawn or
 
 159      modified in future versions of Bison.  */
 
 160   ^"#line "{int}" \"".*"\"\n" {
 
 161     handle_syncline (yytext + sizeof "#line " - 1, *loc);
 
 166   /*----------------------------.
 
 167   | Scanning Bison directives.  |
 
 168   `----------------------------*/
 
 170   /* For directives that are also command line options, the regex must be
 
 172      after "[-_]"s are removed, and the directive must match the --long
 
 173      option name, with a single string argument.  Otherwise, add exceptions
 
 174      to ../build-aux/cross-options.pl.  */
 
 178   "%binary"                         return PERCENT_NONASSOC;
 
 179   "%code"                           return PERCENT_CODE;
 
 180   "%debug"                          return PERCENT_DEBUG;
 
 181   "%default"[-_]"prec"              return PERCENT_DEFAULT_PREC;
 
 182   "%define"                         return PERCENT_DEFINE;
 
 183   "%defines"                        return PERCENT_DEFINES;
 
 184   "%destructor"                     return PERCENT_DESTRUCTOR;
 
 185   "%dprec"                          return PERCENT_DPREC;
 
 186   "%error"[-_]"verbose"             return PERCENT_ERROR_VERBOSE;
 
 187   "%expect"                         return PERCENT_EXPECT;
 
 188   "%expect"[-_]"rr"                 return PERCENT_EXPECT_RR;
 
 189   "%file-prefix"                    return PERCENT_FILE_PREFIX;
 
 190   "%fixed"[-_]"output"[-_]"files"   return PERCENT_YACC;
 
 191   "%initial-action"                 return PERCENT_INITIAL_ACTION;
 
 192   "%glr-parser"                     return PERCENT_GLR_PARSER;
 
 193   "%language"                       return PERCENT_LANGUAGE;
 
 194   "%left"                           return PERCENT_LEFT;
 
 195   "%lex-param"                      return PERCENT_LEX_PARAM;
 
 196   "%locations"                      return PERCENT_LOCATIONS;
 
 197   "%merge"                          return PERCENT_MERGE;
 
 198   "%name"[-_]"prefix"               return PERCENT_NAME_PREFIX;
 
 199   "%no"[-_]"default"[-_]"prec"      return PERCENT_NO_DEFAULT_PREC;
 
 200   "%no"[-_]"lines"                  return PERCENT_NO_LINES;
 
 201   "%nonassoc"                       return PERCENT_NONASSOC;
 
 202   "%nondeterministic-parser"        return PERCENT_NONDETERMINISTIC_PARSER;
 
 203   "%nterm"                          return PERCENT_NTERM;
 
 204   "%output"                         return PERCENT_OUTPUT;
 
 205   "%parse-param"                    return PERCENT_PARSE_PARAM;
 
 206   "%prec"                           return PERCENT_PREC;
 
 207   "%printer"                        return PERCENT_PRINTER;
 
 208   "%pure"[-_]"parser"               return PERCENT_PURE_PARSER;
 
 209   "%require"                        return PERCENT_REQUIRE;
 
 210   "%right"                          return PERCENT_RIGHT;
 
 211   "%skeleton"                       return PERCENT_SKELETON;
 
 212   "%start"                          return PERCENT_START;
 
 213   "%term"                           return PERCENT_TOKEN;
 
 214   "%token"                          return PERCENT_TOKEN;
 
 215   "%token"[-_]"table"               return PERCENT_TOKEN_TABLE;
 
 216   "%type"                           return PERCENT_TYPE;
 
 217   "%union"                          return PERCENT_UNION;
 
 218   "%verbose"                        return PERCENT_VERBOSE;
 
 219   "%yacc"                           return PERCENT_YACC;
 
 222     complain_at (*loc, _("invalid directive: %s"), quote (yytext));
 
 227   ";"                     return SEMICOLON;
 
 228   "<*>"                   return TYPE_TAG_ANY;
 
 229   "<>"                    return TYPE_TAG_NONE;
 
 232     val->uniqstr = uniqstr_new (yytext);
 
 234     bracketed_id_str = NULL;
 
 235     BEGIN SC_AFTER_IDENTIFIER;
 
 239     val->integer = scan_integer (yytext, 10, *loc);
 
 242   0[xX][0-9abcdefABCDEF]+ {
 
 243     val->integer = scan_integer (yytext, 16, *loc);
 
 247   /* Identifiers may not start with a digit.  Yet, don't silently
 
 248      accept "1FOO" as "1 FOO".  */
 
 250     complain_at (*loc, _("invalid identifier: %s"), quote (yytext));
 
 254   "'"         token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
 
 257   "\""        token_start = loc->start; BEGIN SC_ESCAPED_STRING;
 
 260   "%{"        code_start = loc->start; BEGIN SC_PROLOGUE;
 
 262   /* Code in between braces.  */
 
 266     code_start = loc->start;
 
 267     BEGIN SC_BRACED_CODE;
 
 272     obstack_grow (&obstack_for_string, yytext + 1, yyleng - 2);
 
 274     val->uniqstr = uniqstr_new (last_string);
 
 280     static int percent_percent_count;
 
 281     if (++percent_percent_count == 2)
 
 283     return PERCENT_PERCENT;
 
 287     bracketed_id_str = NULL;
 
 288     bracketed_id_start = loc->start;
 
 289     bracketed_id_context_state = YY_START;
 
 290     BEGIN SC_BRACKETED_ID;
 
 294     complain_at (*loc, _("invalid character: %s"), quote (yytext));
 
 298     loc->start = loc->end = scanner_cursor;
 
 304   /*-----------------------------------------------------------------.
 
 305   | Scanning after an identifier, checking whether a colon is next.  |
 
 306   `-----------------------------------------------------------------*/
 
 308 <SC_AFTER_IDENTIFIER>
 
 311     if (bracketed_id_str)
 
 313         ROLLBACK_CURRENT_TOKEN;
 
 314         BEGIN SC_RETURN_BRACKETED_ID;
 
 320         bracketed_id_start = loc->start;
 
 321         bracketed_id_context_state = YY_START;
 
 322         BEGIN SC_BRACKETED_ID;
 
 326     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 331     ROLLBACK_CURRENT_TOKEN;
 
 332     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 337     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 343   /*--------------------------------.
 
 344   | Scanning bracketed identifiers. |
 
 345   `--------------------------------*/
 
 350     if (bracketed_id_str)
 
 352         complain_at (*loc, _("unexpected identifier in bracketed name: %s"),
 
 357         bracketed_id_str = uniqstr_new (yytext);
 
 358         bracketed_id_loc = *loc;
 
 362     BEGIN bracketed_id_context_state;
 
 363     if (bracketed_id_str)
 
 365         if (INITIAL == bracketed_id_context_state)
 
 367             val->uniqstr = bracketed_id_str;
 
 368             bracketed_id_str = 0;
 
 369             *loc = bracketed_id_loc;
 
 374       complain_at (*loc, _("an identifier expected"));
 
 377     complain_at (*loc, _("invalid character in bracketed name: %s"),
 
 381     BEGIN bracketed_id_context_state;
 
 382     unexpected_eof (bracketed_id_start, "]");
 
 386 <SC_RETURN_BRACKETED_ID>
 
 389     ROLLBACK_CURRENT_TOKEN;
 
 390     val->uniqstr = bracketed_id_str;
 
 391     bracketed_id_str = 0;
 
 392     *loc = bracketed_id_loc;
 
 399   /*---------------------------------------------------------------.
 
 400   | Scanning a Yacc comment.  The initial `/ *' is already eaten.  |
 
 401   `---------------------------------------------------------------*/
 
 405   "*/"     BEGIN context_state;
 
 407   <<EOF>>  unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 411   /*------------------------------------------------------------.
 
 412   | Scanning a C comment.  The initial `/ *' is already eaten.  |
 
 413   `------------------------------------------------------------*/
 
 417   "*"{splice}"/"  STRING_GROW; BEGIN context_state;
 
 418   <<EOF>>         unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 422   /*--------------------------------------------------------------.
 
 423   | Scanning a line comment.  The initial `//' is already eaten.  |
 
 424   `--------------------------------------------------------------*/
 
 428   "\n"           STRING_GROW; BEGIN context_state;
 
 429   {splice}       STRING_GROW;
 
 430   <<EOF>>        BEGIN context_state;
 
 434   /*------------------------------------------------.
 
 435   | Scanning a Bison string, including its escapes. |
 
 436   | The initial quote is already eaten.             |
 
 437   `------------------------------------------------*/
 
 442     if (yytext[0] == '\n')
 
 443       unexpected_newline (token_start, "\"");
 
 445     loc->start = token_start;
 
 446     val->chars = last_string;
 
 451     unexpected_eof (token_start, "\"");
 
 453     loc->start = token_start;
 
 454     val->chars = last_string;
 
 460   /*----------------------------------------------------------.
 
 461   | Scanning a Bison character literal, decoding its escapes. |
 
 462   | The initial quote is already eaten.                       |
 
 463   `----------------------------------------------------------*/
 
 465 <SC_ESCAPED_CHARACTER>
 
 469     loc->start = token_start;
 
 470     val->character = last_string[0];
 
 472       /* FIXME: Eventually, make these errors.  */
 
 473       if (last_string[0] == '\0')
 
 475           warn_at (*loc, _("empty character literal"));
 
 476           /* '\0' seems dangerous even if we are about to complain.  */
 
 477           val->character = '\'';
 
 479       else if (last_string[1] != '\0')
 
 480         warn_at (*loc, _("extra characters in character literal"));
 
 482     if (yytext[0] == '\n')
 
 483       unexpected_newline (token_start, "'");
 
 490     loc->start = token_start;
 
 491     val->character = last_string[0];
 
 493       /* FIXME: Eventually, make these errors.  */
 
 494       if (last_string[0] == '\0')
 
 496           warn_at (*loc, _("empty character literal"));
 
 497           /* '\0' seems dangerous even if we are about to complain.  */
 
 498           val->character = '\'';
 
 500       else if (last_string[1] != '\0')
 
 501         warn_at (*loc, _("extra characters in character literal"));
 
 503     unexpected_eof (token_start, "'");
 
 510 <SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING>
 
 512   \0        complain_at (*loc, _("invalid null character"));
 
 516   /*----------------------------.
 
 517   | Decode escaped characters.  |
 
 518   `----------------------------*/
 
 520 <SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
 
 523     unsigned long int c = strtoul (yytext + 1, NULL, 8);
 
 524     if (!c || UCHAR_MAX < c)
 
 525       complain_at (*loc, _("invalid number after \\-escape: %s"),
 
 528       obstack_1grow (&obstack_for_string, c);
 
 531   \\x[0-9abcdefABCDEF]+ {
 
 532     verify (UCHAR_MAX < ULONG_MAX);
 
 533     unsigned long int c = strtoul (yytext + 2, NULL, 16);
 
 534     if (!c || UCHAR_MAX < c)
 
 535       complain_at (*loc, _("invalid number after \\-escape: %s"),
 
 538       obstack_1grow (&obstack_for_string, c);
 
 541   \\a   obstack_1grow (&obstack_for_string, '\a');
 
 542   \\b   obstack_1grow (&obstack_for_string, '\b');
 
 543   \\f   obstack_1grow (&obstack_for_string, '\f');
 
 544   \\n   obstack_1grow (&obstack_for_string, '\n');
 
 545   \\r   obstack_1grow (&obstack_for_string, '\r');
 
 546   \\t   obstack_1grow (&obstack_for_string, '\t');
 
 547   \\v   obstack_1grow (&obstack_for_string, '\v');
 
 549   /* \\[\"\'?\\] would be shorter, but it confuses xgettext.  */
 
 550   \\("\""|"'"|"?"|"\\")  obstack_1grow (&obstack_for_string, yytext[1]);
 
 552   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
 
 553     int c = convert_ucn_to_byte (yytext);
 
 555       complain_at (*loc, _("invalid number after \\-escape: %s"),
 
 558       obstack_1grow (&obstack_for_string, c);
 
 561     char const *p = yytext + 1;
 
 562     /* Quote only if escaping won't make the character visible.  */
 
 563     if (isspace ((unsigned char) *p) && isprint ((unsigned char) *p))
 
 566       p = quotearg_style_mem (escape_quoting_style, p, 1);
 
 567     complain_at (*loc, _("invalid character after \\-escape: %s"), p);
 
 571   /*--------------------------------------------.
 
 572   | Scanning user-code characters and strings.  |
 
 573   `--------------------------------------------*/
 
 575 <SC_CHARACTER,SC_STRING>
 
 577   {splice}|\\{splice}[^\n\[\]]  STRING_GROW;
 
 582   "'"           STRING_GROW; BEGIN context_state;
 
 583   \n            unexpected_newline (token_start, "'"); BEGIN context_state;
 
 584   <<EOF>>       unexpected_eof (token_start, "'"); BEGIN context_state;
 
 589   "\""          STRING_GROW; BEGIN context_state;
 
 590   \n            unexpected_newline (token_start, "\""); BEGIN context_state;
 
 591   <<EOF>>       unexpected_eof (token_start, "\""); BEGIN context_state;
 
 595   /*---------------------------------------------------.
 
 596   | Strings, comments etc. can be found in user code.  |
 
 597   `---------------------------------------------------*/
 
 599 <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
 
 603     context_state = YY_START;
 
 604     token_start = loc->start;
 
 609     context_state = YY_START;
 
 610     token_start = loc->start;
 
 615     context_state = YY_START;
 
 616     token_start = loc->start;
 
 621     context_state = YY_START;
 
 622     BEGIN SC_LINE_COMMENT;
 
 628   /*-----------------------------------------------------------.
 
 629   | Scanning some code in braces (actions). The initial "{" is |
 
 631   `-----------------------------------------------------------*/
 
 635   "{"|"<"{splice}"%"  STRING_GROW; braces_level++;
 
 636   "%"{splice}">"      STRING_GROW; braces_level--;
 
 638     obstack_1grow (&obstack_for_string, '}');
 
 641     if (braces_level < 0)
 
 644         loc->start = code_start;
 
 645         val->code = last_string;
 
 651   /* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
 
 653   "<"{splice}"<"  STRING_GROW;
 
 656     unexpected_eof (code_start, "}");
 
 658     loc->start = code_start;
 
 659     val->code = last_string;
 
 666   /*--------------------------------------------------------------.
 
 667   | Scanning some prologue: from "%{" (already scanned) to "%}".  |
 
 668   `--------------------------------------------------------------*/
 
 674     loc->start = code_start;
 
 675     val->chars = last_string;
 
 681     unexpected_eof (code_start, "%}");
 
 683     loc->start = code_start;
 
 684     val->chars = last_string;
 
 691   /*---------------------------------------------------------------.
 
 692   | Scanning the epilogue (everything after the second "%%", which |
 
 693   | has already been eaten).                                       |
 
 694   `---------------------------------------------------------------*/
 
 700     loc->start = code_start;
 
 701     val->chars = last_string;
 
 708   /*-----------------------------------------------------.
 
 709   | By default, grow the string obstack with the input.  |
 
 710   `-----------------------------------------------------*/
 
 712 <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>.      |
 
 713 <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>\n   STRING_GROW;
 
 717 /* Read bytes from FP into buffer BUF of size SIZE.  Return the
 
 718    number of bytes read.  Remove '\r' from input, treating \r\n
 
 719    and isolated \r as \n.  */
 
 722 no_cr_read (FILE *fp, char *buf, size_t size)
 
 724   size_t bytes_read = fread (buf, 1, size, fp);
 
 727       char *w = memchr (buf, '\r', bytes_read);
 
 731           char const *lim = buf + bytes_read;
 
 735               /* Found an '\r'.  Treat it like '\n', but ignore any
 
 736                  '\n' that immediately follows.  */
 
 741                   if (ch != '\n' && ungetc (ch, fp) != ch)
 
 747               /* Copy until the next '\r'.  */
 
 753               while ((*w++ = *r++) != '\r');
 
 765 /*------------------------------------------------------.
 
 766 | Scan NUMBER for a base-BASE integer at location LOC.  |
 
 767 `------------------------------------------------------*/
 
 769 static unsigned long int
 
 770 scan_integer (char const *number, int base, location loc)
 
 772   verify (INT_MAX < ULONG_MAX);
 
 773   unsigned long int num = strtoul (number, NULL, base);
 
 777       complain_at (loc, _("integer out of range: %s"), quote (number));
 
 785 /*------------------------------------------------------------------.
 
 786 | Convert universal character name UCN to a single-byte character,  |
 
 787 | and return that character.  Return -1 if UCN does not correspond  |
 
 788 | to a single-byte character.                                       |
 
 789 `------------------------------------------------------------------*/
 
 792 convert_ucn_to_byte (char const *ucn)
 
 794   verify (UCHAR_MAX <= INT_MAX);
 
 795   unsigned long int code = strtoul (ucn + 2, NULL, 16);
 
 797   /* FIXME: Currently we assume Unicode-compatible unibyte characters
 
 798      on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes).  On
 
 799      non-ASCII hosts we support only the portable C character set.
 
 800      These limitations should be removed once we add support for
 
 801      multibyte characters.  */
 
 803   if (UCHAR_MAX < code)
 
 806 #if ! ('$' == 0x24 && '@' == 0x40 && '`' == 0x60 && '~' == 0x7e)
 
 808     /* A non-ASCII host.  Use CODE to index into a table of the C
 
 809        basic execution character set, which is guaranteed to exist on
 
 810        all Standard C platforms.  This table also includes '$', '@',
 
 811        and '`', which are not in the basic execution character set but
 
 812        which are unibyte characters on all the platforms that we know
 
 814     static signed char const table[] =
 
 816         '\0',   -1,   -1,   -1,   -1,   -1,   -1, '\a',
 
 817         '\b', '\t', '\n', '\v', '\f', '\r',   -1,   -1,
 
 818           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 819           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 820          ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
 
 821          '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
 
 822          '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
 
 823          '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
 
 824          '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',
 
 825          'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
 
 826          'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
 
 827          'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_',
 
 828          '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
 
 829          'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
 
 830          'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
 
 831          'x',  'y',  'z',  '{',  '|',  '}',  '~'
 
 834     code = code < sizeof table ? table[code] : -1;
 
 842 /*----------------------------------------------------------------.
 
 843 | Handle `#line INT "FILE"'.  ARGS has already skipped `#line '.  |
 
 844 `----------------------------------------------------------------*/
 
 847 handle_syncline (char *args, location loc)
 
 850   unsigned long int lineno = strtoul (args, &after_num, 10);
 
 851   char *file = mbschr (after_num, '"') + 1;
 
 852   *mbschr (file, '"') = '\0';
 
 853   if (INT_MAX <= lineno)
 
 855       warn_at (loc, _("line number overflow"));
 
 858   current_file = uniqstr_new (file);
 
 859   boundary_set (&scanner_cursor, current_file, lineno, 1);
 
 863 /*----------------------------------------------------------------.
 
 864 | For a token or comment starting at START, report message MSGID, |
 
 865 | which should say that an end marker was found before            |
 
 866 | the expected TOKEN_END.                                         |
 
 867 `----------------------------------------------------------------*/
 
 870 unexpected_end (boundary start, char const *msgid, char const *token_end)
 
 874   loc.end = scanner_cursor;
 
 875   complain_at (loc, _(msgid), token_end);
 
 879 /*------------------------------------------------------------------------.
 
 880 | Report an unexpected EOF in a token or comment starting at START.       |
 
 881 | An end of file was encountered and the expected TOKEN_END was missing.  |
 
 882 `------------------------------------------------------------------------*/
 
 885 unexpected_eof (boundary start, char const *token_end)
 
 887   unexpected_end (start, N_("missing `%s' at end of file"), token_end);
 
 891 /*----------------------------------------.
 
 892 | Likewise, but for unexpected newlines.  |
 
 893 `----------------------------------------*/
 
 896 unexpected_newline (boundary start, char const *token_end)
 
 898   unexpected_end (start, N_("missing `%s' at end of line"), token_end);
 
 902 /*-------------------------.
 
 903 | Initialize the scanner.  |
 
 904 `-------------------------*/
 
 907 gram_scanner_initialize (void)
 
 909   obstack_init (&obstack_for_string);
 
 913 /*-----------------------------------------------.
 
 914 | Free all the memory allocated to the scanner.  |
 
 915 `-----------------------------------------------*/
 
 918 gram_scanner_free (void)
 
 920   obstack_free (&obstack_for_string, 0);
 
 921   /* Reclaim Flex's buffers.  */