1 /* Bison Grammar Scanner                             -*- C -*-
 
   3    Copyright (C) 2002-2010 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 <src/flex-scanner.h>
 
  32 #include <src/complain.h>
 
  33 #include <src/files.h>
 
  36 #include <src/reader.h>
 
  37 #include <src/uniqstr.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)       \
 
  70 #define ROLLBACK_CURRENT_TOKEN                                  \
 
  72     scanner_cursor.column -= mbsnwidth (yytext, yyleng, 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;
 
  86 gram_scanner_last_string_free (void)
 
  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. */
 
 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. */
 
 108  /* Three 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 %x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE
 
 113  /* C and C++ comments in code. */
 
 114 %x SC_COMMENT SC_LINE_COMMENT
 
 115  /* Strings and characters in code. */
 
 116 %x SC_STRING SC_CHARACTER
 
 117  /* Bracketed identifiers support. */
 
 118 %x SC_BRACKETED_ID SC_RETURN_BRACKETED_ID
 
 120 letter    [-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
 
 121 id        {letter}({letter}|[0-9])*
 
 125 /* POSIX says that a tag must be both an id and a C union member, but
 
 126    historically almost any character is allowed in a tag.  We disallow
 
 127    NUL, as this simplifies our implementation.  We disallow angle
 
 128    bracket to match them in nested pairs: several languages use them
 
 129    for generics/template types.  */
 
 132 /* Zero or more instances of backslash-newline.  Following GCC, allow
 
 133    white space between the backslash and the newline.  */
 
 134 splice   (\\[ \f\t\v]*\n)*
 
 138   /* Nesting level.  Either for nested braces, or nested angle brackets
 
 140   int nesting IF_LINT (= 0);
 
 142   /* Parent context state, when applicable.  */
 
 143   int context_state IF_LINT (= 0);
 
 145   /* Location of most recent identifier, when applicable.  */
 
 146   location id_loc IF_LINT (= empty_location);
 
 148   /* Where containing code started, when applicable.  Its initial
 
 149      value is relevant only when yylex is invoked in the SC_EPILOGUE
 
 151   boundary code_start = scanner_cursor;
 
 153   /* Where containing comment or string or character literal started,
 
 155   boundary token_start IF_LINT (= scanner_cursor);
 
 159   /*-----------------------.
 
 160   | Scanning white space.  |
 
 161   `-----------------------*/
 
 163 <INITIAL,SC_AFTER_IDENTIFIER,SC_BRACKETED_ID,SC_RETURN_BRACKETED_ID>
 
 165   /* Comments and white space.  */
 
 166   ","          warn_at (*loc, _("stray `,' treated as white space"));
 
 170     token_start = loc->start;
 
 171     context_state = YY_START;
 
 172     BEGIN SC_YACC_COMMENT;
 
 175   /* #line directives are not documented, and may be withdrawn or
 
 176      modified in future versions of Bison.  */
 
 177   ^"#line "{int}" \"".*"\"\n" {
 
 178     handle_syncline (yytext + sizeof "#line " - 1, *loc);
 
 183   /*----------------------------.
 
 184   | Scanning Bison directives.  |
 
 185   `----------------------------*/
 
 187   /* For directives that are also command line options, the regex must be
 
 189      after "[-_]"s are removed, and the directive must match the --long
 
 190      option name, with a single string argument.  Otherwise, add exceptions
 
 191      to ../build-aux/cross-options.pl.  */
 
 195   "%binary"                         return PERCENT_NONASSOC;
 
 196   "%code"                           return PERCENT_CODE;
 
 197   "%debug"                          RETURN_PERCENT_FLAG("parse.trace");
 
 198   "%default"[-_]"prec"              return PERCENT_DEFAULT_PREC;
 
 199   "%define"                         return PERCENT_DEFINE;
 
 200   "%defines"                        return PERCENT_DEFINES;
 
 201   "%destructor"                     return PERCENT_DESTRUCTOR;
 
 202   "%dprec"                          return PERCENT_DPREC;
 
 203   "%error"[-_]"verbose"             return PERCENT_ERROR_VERBOSE;
 
 204   "%expect"                         return PERCENT_EXPECT;
 
 205   "%expect"[-_]"rr"                 return PERCENT_EXPECT_RR;
 
 206   "%file-prefix"                    return PERCENT_FILE_PREFIX;
 
 207   "%fixed"[-_]"output"[-_]"files"   return PERCENT_YACC;
 
 208   "%initial-action"                 return PERCENT_INITIAL_ACTION;
 
 209   "%glr-parser"                     return PERCENT_GLR_PARSER;
 
 210   "%language"                       return PERCENT_LANGUAGE;
 
 211   "%left"                           return PERCENT_LEFT;
 
 212   "%lex-param"                      RETURN_PERCENT_PARAM(lex);
 
 213   "%locations"                      RETURN_PERCENT_FLAG("locations");
 
 214   "%merge"                          return PERCENT_MERGE;
 
 215   "%name"[-_]"prefix"               return PERCENT_NAME_PREFIX;
 
 216   "%no"[-_]"default"[-_]"prec"      return PERCENT_NO_DEFAULT_PREC;
 
 217   "%no"[-_]"lines"                  return PERCENT_NO_LINES;
 
 218   "%nonassoc"                       return PERCENT_NONASSOC;
 
 219   "%nondeterministic-parser"        return PERCENT_NONDETERMINISTIC_PARSER;
 
 220   "%nterm"                          return PERCENT_NTERM;
 
 221   "%output"                         return PERCENT_OUTPUT;
 
 222   "%param"                          RETURN_PERCENT_PARAM(both);
 
 223   "%parse-param"                    RETURN_PERCENT_PARAM(parse);
 
 224   "%prec"                           return PERCENT_PREC;
 
 225   "%precedence"                     return PERCENT_PRECEDENCE;
 
 226   "%printer"                        return PERCENT_PRINTER;
 
 227   "%pure"[-_]"parser"               RETURN_PERCENT_FLAG("api.pure");
 
 228   "%require"                        return PERCENT_REQUIRE;
 
 229   "%right"                          return PERCENT_RIGHT;
 
 230   "%skeleton"                       return PERCENT_SKELETON;
 
 231   "%start"                          return PERCENT_START;
 
 232   "%term"                           return PERCENT_TOKEN;
 
 233   "%token"                          return PERCENT_TOKEN;
 
 234   "%token"[-_]"table"               return PERCENT_TOKEN_TABLE;
 
 235   "%type"                           return PERCENT_TYPE;
 
 236   "%union"                          return PERCENT_UNION;
 
 237   "%verbose"                        return PERCENT_VERBOSE;
 
 238   "%yacc"                           return PERCENT_YACC;
 
 241     complain_at (*loc, _("invalid directive: %s"), quote (yytext));
 
 246   ";"                     return SEMICOLON;
 
 249     val->uniqstr = uniqstr_new (yytext);
 
 251     bracketed_id_str = NULL;
 
 252     BEGIN SC_AFTER_IDENTIFIER;
 
 256     val->integer = scan_integer (yytext, 10, *loc);
 
 259   0[xX][0-9abcdefABCDEF]+ {
 
 260     val->integer = scan_integer (yytext, 16, *loc);
 
 264   /* Identifiers may not start with a digit.  Yet, don't silently
 
 265      accept "1FOO" as "1 FOO".  */
 
 267     complain_at (*loc, _("invalid identifier: %s"), quote (yytext));
 
 271   "'"         token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
 
 274   "\""        token_start = loc->start; BEGIN SC_ESCAPED_STRING;
 
 277   "%{"        code_start = loc->start; BEGIN SC_PROLOGUE;
 
 279   /* Code in between braces.  */
 
 283     code_start = loc->start;
 
 284     BEGIN SC_BRACED_CODE;
 
 288   "<*>"       return TAG_ANY;
 
 289   "<>"        return TAG_NONE;
 
 291     obstack_grow (&obstack_for_string, yytext + 1, yyleng - 2);
 
 293     val->uniqstr = uniqstr_new (last_string);
 
 299     token_start = loc->start;
 
 304     static int percent_percent_count;
 
 305     if (++percent_percent_count == 2)
 
 307     return PERCENT_PERCENT;
 
 311     bracketed_id_str = NULL;
 
 312     bracketed_id_start = loc->start;
 
 313     bracketed_id_context_state = YY_START;
 
 314     BEGIN SC_BRACKETED_ID;
 
 318     complain_at (*loc, _("invalid character: %s"), quote (yytext));
 
 322     loc->start = loc->end = scanner_cursor;
 
 328   /*--------------------------------------------------------------.
 
 329   | Supporting \0 complexifies our implementation for no expected |
 
 331   `--------------------------------------------------------------*/
 
 333 <SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING,SC_TAG>
 
 335   \0        complain_at (*loc, _("invalid null character"));
 
 339   /*-----------------------------------------------------------------.
 
 340   | Scanning after an identifier, checking whether a colon is next.  |
 
 341   `-----------------------------------------------------------------*/
 
 343 <SC_AFTER_IDENTIFIER>
 
 346     if (bracketed_id_str)
 
 348         ROLLBACK_CURRENT_TOKEN;
 
 349         BEGIN SC_RETURN_BRACKETED_ID;
 
 355         bracketed_id_start = loc->start;
 
 356         bracketed_id_context_state = YY_START;
 
 357         BEGIN SC_BRACKETED_ID;
 
 361     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 366     ROLLBACK_CURRENT_TOKEN;
 
 367     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 372     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 378   /*--------------------------------.
 
 379   | Scanning bracketed identifiers. |
 
 380   `--------------------------------*/
 
 385     if (bracketed_id_str)
 
 387         complain_at (*loc, _("unexpected identifier in bracketed name: %s"),
 
 392         bracketed_id_str = uniqstr_new (yytext);
 
 393         bracketed_id_loc = *loc;
 
 397     BEGIN bracketed_id_context_state;
 
 398     if (bracketed_id_str)
 
 400         if (INITIAL == bracketed_id_context_state)
 
 402             val->uniqstr = bracketed_id_str;
 
 403             bracketed_id_str = 0;
 
 404             *loc = bracketed_id_loc;
 
 409       complain_at (*loc, _("an identifier expected"));
 
 412     complain_at (*loc, _("invalid character in bracketed name: %s"),
 
 416     BEGIN bracketed_id_context_state;
 
 417     unexpected_eof (bracketed_id_start, "]");
 
 421 <SC_RETURN_BRACKETED_ID>
 
 424     ROLLBACK_CURRENT_TOKEN;
 
 425     val->uniqstr = bracketed_id_str;
 
 426     bracketed_id_str = 0;
 
 427     *loc = bracketed_id_loc;
 
 434   /*---------------------------------------------------------------.
 
 435   | Scanning a Yacc comment.  The initial `/ *' is already eaten.  |
 
 436   `---------------------------------------------------------------*/
 
 440   "*/"     BEGIN context_state;
 
 442   <<EOF>>  unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 446   /*------------------------------------------------------------.
 
 447   | Scanning a C comment.  The initial `/ *' is already eaten.  |
 
 448   `------------------------------------------------------------*/
 
 452   "*"{splice}"/"  STRING_GROW; BEGIN context_state;
 
 453   <<EOF>>         unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 457   /*--------------------------------------------------------------.
 
 458   | Scanning a line comment.  The initial `//' is already eaten.  |
 
 459   `--------------------------------------------------------------*/
 
 463   "\n"           STRING_GROW; BEGIN context_state;
 
 464   {splice}       STRING_GROW;
 
 465   <<EOF>>        BEGIN context_state;
 
 469   /*------------------------------------------------.
 
 470   | Scanning a Bison string, including its escapes. |
 
 471   | The initial quote is already eaten.             |
 
 472   `------------------------------------------------*/
 
 477     if (yytext[0] == '\n')
 
 478       unexpected_newline (token_start, "\"");
 
 480     loc->start = token_start;
 
 481     val->chars = last_string;
 
 486     unexpected_eof (token_start, "\"");
 
 488     loc->start = token_start;
 
 489     val->chars = last_string;
 
 495   /*----------------------------------------------------------.
 
 496   | Scanning a Bison character literal, decoding its escapes. |
 
 497   | The initial quote is already eaten.                       |
 
 498   `----------------------------------------------------------*/
 
 500 <SC_ESCAPED_CHARACTER>
 
 504     loc->start = token_start;
 
 505     val->character = last_string[0];
 
 507       /* FIXME: Eventually, make these errors.  */
 
 508       if (last_string[0] == '\0')
 
 510           warn_at (*loc, _("empty character literal"));
 
 511           /* '\0' seems dangerous even if we are about to complain.  */
 
 512           val->character = '\'';
 
 514       else if (last_string[1] != '\0')
 
 515         warn_at (*loc, _("extra characters in character literal"));
 
 517     if (yytext[0] == '\n')
 
 518       unexpected_newline (token_start, "'");
 
 525     loc->start = token_start;
 
 526     val->character = last_string[0];
 
 528       /* FIXME: Eventually, make these errors.  */
 
 529       if (last_string[0] == '\0')
 
 531           warn_at (*loc, _("empty character literal"));
 
 532           /* '\0' seems dangerous even if we are about to complain.  */
 
 533           val->character = '\'';
 
 535       else if (last_string[1] != '\0')
 
 536         warn_at (*loc, _("extra characters in character literal"));
 
 538     unexpected_eof (token_start, "'");
 
 545   /*-----------------------------------------------------------.
 
 546   | Scanning a Bison nested tag.  The initial angle bracket is |
 
 548   `-----------------------------------------------------------*/
 
 557         loc->start = token_start;
 
 558         val->uniqstr = uniqstr_new (last_string);
 
 567   "<"+   STRING_GROW; nesting += yyleng;
 
 570     unexpected_eof (token_start, ">");
 
 572     loc->start = token_start;
 
 573     val->uniqstr = uniqstr_new (last_string);
 
 580   /*----------------------------.
 
 581   | Decode escaped characters.  |
 
 582   `----------------------------*/
 
 584 <SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
 
 587     unsigned long int c = strtoul (yytext + 1, NULL, 8);
 
 588     if (!c || UCHAR_MAX < c)
 
 589       complain_at (*loc, _("invalid number after \\-escape: %s"),
 
 592       obstack_1grow (&obstack_for_string, c);
 
 595   \\x[0-9abcdefABCDEF]+ {
 
 596     verify (UCHAR_MAX < ULONG_MAX);
 
 597     unsigned long int c = strtoul (yytext + 2, NULL, 16);
 
 598     if (!c || UCHAR_MAX < c)
 
 599       complain_at (*loc, _("invalid number after \\-escape: %s"),
 
 602       obstack_1grow (&obstack_for_string, c);
 
 605   \\a   obstack_1grow (&obstack_for_string, '\a');
 
 606   \\b   obstack_1grow (&obstack_for_string, '\b');
 
 607   \\f   obstack_1grow (&obstack_for_string, '\f');
 
 608   \\n   obstack_1grow (&obstack_for_string, '\n');
 
 609   \\r   obstack_1grow (&obstack_for_string, '\r');
 
 610   \\t   obstack_1grow (&obstack_for_string, '\t');
 
 611   \\v   obstack_1grow (&obstack_for_string, '\v');
 
 613   /* \\[\"\'?\\] would be shorter, but it confuses xgettext.  */
 
 614   \\("\""|"'"|"?"|"\\")  obstack_1grow (&obstack_for_string, yytext[1]);
 
 616   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
 
 617     int c = convert_ucn_to_byte (yytext);
 
 619       complain_at (*loc, _("invalid number after \\-escape: %s"),
 
 622       obstack_1grow (&obstack_for_string, c);
 
 625     char const *p = yytext + 1;
 
 626     /* Quote only if escaping won't make the character visible.  */
 
 627     if (isspace ((unsigned char) *p) && isprint ((unsigned char) *p))
 
 630       p = quotearg_style_mem (escape_quoting_style, p, 1);
 
 631     complain_at (*loc, _("invalid character after \\-escape: %s"), p);
 
 635   /*--------------------------------------------.
 
 636   | Scanning user-code characters and strings.  |
 
 637   `--------------------------------------------*/
 
 639 <SC_CHARACTER,SC_STRING>
 
 641   {splice}|\\{splice}[^\n\[\]]  STRING_GROW;
 
 646   "'"           STRING_GROW; BEGIN context_state;
 
 647   \n            unexpected_newline (token_start, "'"); BEGIN context_state;
 
 648   <<EOF>>       unexpected_eof (token_start, "'"); BEGIN context_state;
 
 653   "\""          STRING_GROW; BEGIN context_state;
 
 654   \n            unexpected_newline (token_start, "\""); BEGIN context_state;
 
 655   <<EOF>>       unexpected_eof (token_start, "\""); BEGIN context_state;
 
 659   /*---------------------------------------------------.
 
 660   | Strings, comments etc. can be found in user code.  |
 
 661   `---------------------------------------------------*/
 
 663 <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
 
 667     context_state = YY_START;
 
 668     token_start = loc->start;
 
 673     context_state = YY_START;
 
 674     token_start = loc->start;
 
 679     context_state = YY_START;
 
 680     token_start = loc->start;
 
 685     context_state = YY_START;
 
 686     BEGIN SC_LINE_COMMENT;
 
 692   /*-----------------------------------------------------------.
 
 693   | Scanning some code in braces (actions). The initial "{" is |
 
 695   `-----------------------------------------------------------*/
 
 699   "{"|"<"{splice}"%"  STRING_GROW; nesting++;
 
 700   "%"{splice}">"      STRING_GROW; nesting--;
 
 702     obstack_1grow (&obstack_for_string, '}');
 
 708         loc->start = code_start;
 
 709         val->code = last_string;
 
 715   /* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
 
 717   "<"{splice}"<"  STRING_GROW;
 
 720     unexpected_eof (code_start, "}");
 
 722     loc->start = code_start;
 
 723     val->code = last_string;
 
 730   /*--------------------------------------------------------------.
 
 731   | Scanning some prologue: from "%{" (already scanned) to "%}".  |
 
 732   `--------------------------------------------------------------*/
 
 738     loc->start = code_start;
 
 739     val->chars = last_string;
 
 745     unexpected_eof (code_start, "%}");
 
 747     loc->start = code_start;
 
 748     val->chars = last_string;
 
 755   /*---------------------------------------------------------------.
 
 756   | Scanning the epilogue (everything after the second "%%", which |
 
 757   | has already been eaten).                                       |
 
 758   `---------------------------------------------------------------*/
 
 764     loc->start = code_start;
 
 765     val->chars = last_string;
 
 772   /*-----------------------------------------------------.
 
 773   | By default, grow the string obstack with the input.  |
 
 774   `-----------------------------------------------------*/
 
 776 <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>.      |
 
 777 <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>\n   STRING_GROW;
 
 781 /* Read bytes from FP into buffer BUF of size SIZE.  Return the
 
 782    number of bytes read.  Remove '\r' from input, treating \r\n
 
 783    and isolated \r as \n.  */
 
 786 no_cr_read (FILE *fp, char *buf, size_t size)
 
 788   size_t bytes_read = fread (buf, 1, size, fp);
 
 791       char *w = memchr (buf, '\r', bytes_read);
 
 795           char const *lim = buf + bytes_read;
 
 799               /* Found an '\r'.  Treat it like '\n', but ignore any
 
 800                  '\n' that immediately follows.  */
 
 805                   if (ch != '\n' && ungetc (ch, fp) != ch)
 
 811               /* Copy until the next '\r'.  */
 
 817               while ((*w++ = *r++) != '\r');
 
 829 /*------------------------------------------------------.
 
 830 | Scan NUMBER for a base-BASE integer at location LOC.  |
 
 831 `------------------------------------------------------*/
 
 833 static unsigned long int
 
 834 scan_integer (char const *number, int base, location loc)
 
 836   verify (INT_MAX < ULONG_MAX);
 
 837   unsigned long int num = strtoul (number, NULL, base);
 
 841       complain_at (loc, _("integer out of range: %s"), quote (number));
 
 849 /*------------------------------------------------------------------.
 
 850 | Convert universal character name UCN to a single-byte character,  |
 
 851 | and return that character.  Return -1 if UCN does not correspond  |
 
 852 | to a single-byte character.                                       |
 
 853 `------------------------------------------------------------------*/
 
 856 convert_ucn_to_byte (char const *ucn)
 
 858   verify (UCHAR_MAX <= INT_MAX);
 
 859   unsigned long int code = strtoul (ucn + 2, NULL, 16);
 
 861   /* FIXME: Currently we assume Unicode-compatible unibyte characters
 
 862      on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes).  On
 
 863      non-ASCII hosts we support only the portable C character set.
 
 864      These limitations should be removed once we add support for
 
 865      multibyte characters.  */
 
 867   if (UCHAR_MAX < code)
 
 870 #if ! ('$' == 0x24 && '@' == 0x40 && '`' == 0x60 && '~' == 0x7e)
 
 872     /* A non-ASCII host.  Use CODE to index into a table of the C
 
 873        basic execution character set, which is guaranteed to exist on
 
 874        all Standard C platforms.  This table also includes '$', '@',
 
 875        and '`', which are not in the basic execution character set but
 
 876        which are unibyte characters on all the platforms that we know
 
 878     static signed char const table[] =
 
 880         '\0',   -1,   -1,   -1,   -1,   -1,   -1, '\a',
 
 881         '\b', '\t', '\n', '\v', '\f', '\r',   -1,   -1,
 
 882           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 883           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 884          ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
 
 885          '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
 
 886          '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
 
 887          '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
 
 888          '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',
 
 889          'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
 
 890          'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
 
 891          'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_',
 
 892          '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
 
 893          'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
 
 894          'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
 
 895          'x',  'y',  'z',  '{',  '|',  '}',  '~'
 
 898     code = code < sizeof table ? table[code] : -1;
 
 906 /*----------------------------------------------------------------.
 
 907 | Handle `#line INT "FILE"'.  ARGS has already skipped `#line '.  |
 
 908 `----------------------------------------------------------------*/
 
 911 handle_syncline (char *args, location loc)
 
 914   unsigned long int lineno = strtoul (args, &after_num, 10);
 
 915   char *file = strchr (after_num, '"') + 1;
 
 916   *strchr (file, '"') = '\0';
 
 917   if (INT_MAX <= lineno)
 
 919       warn_at (loc, _("line number overflow"));
 
 922   current_file = uniqstr_new (file);
 
 923   boundary_set (&scanner_cursor, current_file, lineno, 1);
 
 927 /*----------------------------------------------------------------.
 
 928 | For a token or comment starting at START, report message MSGID, |
 
 929 | which should say that an end marker was found before            |
 
 930 | the expected TOKEN_END.                                         |
 
 931 `----------------------------------------------------------------*/
 
 934 unexpected_end (boundary start, char const *msgid, char const *token_end)
 
 938   loc.end = scanner_cursor;
 
 939   complain_at (loc, _(msgid), token_end);
 
 943 /*------------------------------------------------------------------------.
 
 944 | Report an unexpected EOF in a token or comment starting at START.       |
 
 945 | An end of file was encountered and the expected TOKEN_END was missing.  |
 
 946 `------------------------------------------------------------------------*/
 
 949 unexpected_eof (boundary start, char const *token_end)
 
 951   unexpected_end (start, N_("missing `%s' at end of file"), token_end);
 
 955 /*----------------------------------------.
 
 956 | Likewise, but for unexpected newlines.  |
 
 957 `----------------------------------------*/
 
 960 unexpected_newline (boundary start, char const *token_end)
 
 962   unexpected_end (start, N_("missing `%s' at end of line"), token_end);
 
 966 /*-------------------------.
 
 967 | Initialize the scanner.  |
 
 968 `-------------------------*/
 
 971 gram_scanner_initialize (void)
 
 973   obstack_init (&obstack_for_string);
 
 977 /*-----------------------------------------------.
 
 978 | Free all the memory allocated to the scanner.  |
 
 979 `-----------------------------------------------*/
 
 982 gram_scanner_free (void)
 
 984   obstack_free (&obstack_for_string, 0);
 
 985   /* Reclaim Flex's buffers.  */