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 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>
 
  34 #include <src/getargs.h>
 
  37 #include <src/reader.h>
 
  38 #include <src/uniqstr.h>
 
  44 #include <src/scan-gram.h>
 
  46 #define YY_DECL GRAM_LEX_DECL
 
  48 #define YY_USER_INIT                                    \
 
  49    code_start = scanner_cursor = loc->start;            \
 
  51 /* Location of scanner cursor.  */
 
  52 static boundary scanner_cursor;
 
  54 #define YY_USER_ACTION  location_compute (loc, &scanner_cursor, yytext, yyleng);
 
  56 static size_t no_cr_read (FILE *, char *, size_t);
 
  57 #define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
 
  59 #define RETURN_PERCENT_PARAM(Value)                     \
 
  60   RETURN_VALUE(PERCENT_PARAM, param, param_ ## Value)
 
  62 #define RETURN_PERCENT_FLAG(Value)                              \
 
  63   RETURN_VALUE(PERCENT_FLAG, uniqstr, uniqstr_new (Value))
 
  65 #define RETURN_VALUE(Token, Field, Value)       \
 
  71 #define ROLLBACK_CURRENT_TOKEN                                  \
 
  73     scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);     \
 
  77 #define DEPRECATED(Msg)                                         \
 
  80     complain (loc, Wdeprecated,                                 \
 
  81               _("deprecated directive: %s, use %s"),            \
 
  82               quote (yytext), quote_n (1, Msg));                \
 
  83     scanner_cursor.column -= mbsnwidth (Msg, strlen (Msg), 0);  \
 
  84     for (i = strlen (Msg); i != 0; --i)                         \
 
  88 /* A string representing the most recently saved token.  */
 
  89 static char *last_string;
 
  91 /* Bracketed identifier. */
 
  92 static uniqstr bracketed_id_str = 0;
 
  93 static location bracketed_id_loc;
 
  94 static boundary bracketed_id_start;
 
  95 static int bracketed_id_context_state = 0;
 
  98 gram_scanner_last_string_free (void)
 
 103 static void handle_syncline (char *, location);
 
 104 static unsigned long int scan_integer (char const *p, int base, location loc);
 
 105 static int convert_ucn_to_byte (char const *hex_text);
 
 106 static void unexpected_eof (boundary, char const *);
 
 107 static void unexpected_newline (boundary, char const *);
 
 110  /* A C-like comment in directives/rules. */
 
 112  /* Strings and characters in directives/rules. */
 
 113 %x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
 
 114  /* A identifier was just read in directives/rules.  Special state
 
 115     to capture the sequence 'identifier :'. */
 
 116 %x SC_AFTER_IDENTIFIER
 
 117  /* A complex tag, with nested angles brackets. */
 
 120  /* Four types of user code:
 
 121     - prologue (code between '%{' '%}' in the first section, before %%);
 
 122     - actions, printers, union, etc, (between braced in the middle section);
 
 123     - epilogue (everything after the second %%).
 
 124     - predicate (code between '%?{' and '{' in middle section); */
 
 125 %x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE SC_PREDICATE
 
 126  /* C and C++ comments in code. */
 
 127 %x SC_COMMENT SC_LINE_COMMENT
 
 128  /* Strings and characters in code. */
 
 129 %x SC_STRING SC_CHARACTER
 
 130  /* Bracketed identifiers support. */
 
 131 %x SC_BRACKETED_ID SC_RETURN_BRACKETED_ID
 
 133 letter    [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
 
 134 id        {letter}({letter}|[-0-9])*
 
 138 /* POSIX says that a tag must be both an id and a C union member, but
 
 139    historically almost any character is allowed in a tag.  We disallow
 
 140    NUL, as this simplifies our implementation.  We disallow angle
 
 141    bracket to match them in nested pairs: several languages use them
 
 142    for generics/template types.  */
 
 145 /* Zero or more instances of backslash-newline.  Following GCC, allow
 
 146    white space between the backslash and the newline.  */
 
 147 splice   (\\[ \f\t\v]*\n)*
 
 149 /* An equal sign, with optional leading whitespaces. This is used in some
 
 150    deprecated constructs. */
 
 151 eqopt    ([[:space:]]*=)?
 
 155   /* Nesting level.  Either for nested braces, or nested angle brackets
 
 157   int nesting PACIFY_CC (= 0);
 
 159   /* Parent context state, when applicable.  */
 
 160   int context_state PACIFY_CC (= 0);
 
 162   /* Location of most recent identifier, when applicable.  */
 
 163   location id_loc PACIFY_CC (= empty_location);
 
 165   /* Where containing code started, when applicable.  Its initial
 
 166      value is relevant only when yylex is invoked in the SC_EPILOGUE
 
 168   boundary code_start = scanner_cursor;
 
 170   /* Where containing comment or string or character literal started,
 
 172   boundary token_start PACIFY_CC (= scanner_cursor);
 
 176   /*-----------------------.
 
 177   | Scanning white space.  |
 
 178   `-----------------------*/
 
 180 <INITIAL,SC_AFTER_IDENTIFIER,SC_BRACKETED_ID,SC_RETURN_BRACKETED_ID>
 
 182   /* Comments and white space.  */
 
 184      complain (loc, Wother, _("stray ',' treated as white space"));
 
 189     token_start = loc->start;
 
 190     context_state = YY_START;
 
 191     BEGIN SC_YACC_COMMENT;
 
 194   /* #line directives are not documented, and may be withdrawn or
 
 195      modified in future versions of Bison.  */
 
 196   ^"#line "{int}" \"".*"\"\n" {
 
 197     handle_syncline (yytext + sizeof "#line " - 1, *loc);
 
 202   /*----------------------------.
 
 203   | Scanning Bison directives.  |
 
 204   `----------------------------*/
 
 206   /* For directives that are also command line options, the regex must be
 
 208      after "[-_]"s are removed, and the directive must match the --long
 
 209      option name, with a single string argument.  Otherwise, add exceptions
 
 210      to ../build-aux/cross-options.pl.  */
 
 214   "%binary"                         return PERCENT_NONASSOC;
 
 215   "%code"                           return PERCENT_CODE;
 
 216   "%debug"                          RETURN_PERCENT_FLAG("parse.trace");
 
 217   "%default-prec"                   return PERCENT_DEFAULT_PREC;
 
 218   "%define"                         return PERCENT_DEFINE;
 
 219   "%defines"                        return PERCENT_DEFINES;
 
 220   "%destructor"                     return PERCENT_DESTRUCTOR;
 
 221   "%dprec"                          return PERCENT_DPREC;
 
 222   "%error-verbose"                  return PERCENT_ERROR_VERBOSE;
 
 223   "%expect"                         return PERCENT_EXPECT;
 
 224   "%expect-rr"                      return PERCENT_EXPECT_RR;
 
 225   "%file-prefix"                    return PERCENT_FILE_PREFIX;
 
 226   "%fixed-output-files"             return PERCENT_YACC;
 
 227   "%initial-action"                 return PERCENT_INITIAL_ACTION;
 
 228   "%glr-parser"                     return PERCENT_GLR_PARSER;
 
 229   "%language"                       return PERCENT_LANGUAGE;
 
 230   "%left"                           return PERCENT_LEFT;
 
 231   "%lex-param"                      RETURN_PERCENT_PARAM(lex);
 
 232   "%locations"                      RETURN_PERCENT_FLAG("locations");
 
 233   "%merge"                          return PERCENT_MERGE;
 
 234   "%name-prefix"                    return PERCENT_NAME_PREFIX;
 
 235   "%no-default-prec"                return PERCENT_NO_DEFAULT_PREC;
 
 236   "%no-lines"                       return PERCENT_NO_LINES;
 
 237   "%nonassoc"                       return PERCENT_NONASSOC;
 
 238   "%nondeterministic-parser"        return PERCENT_NONDETERMINISTIC_PARSER;
 
 239   "%nterm"                          return PERCENT_NTERM;
 
 240   "%output"                         return PERCENT_OUTPUT;
 
 241   "%param"                          RETURN_PERCENT_PARAM(both);
 
 242   "%parse-param"                    RETURN_PERCENT_PARAM(parse);
 
 243   "%prec"                           return PERCENT_PREC;
 
 244   "%precedence"                     return PERCENT_PRECEDENCE;
 
 245   "%printer"                        return PERCENT_PRINTER;
 
 246   "%pure-parser"                    RETURN_PERCENT_FLAG("api.pure");
 
 247   "%require"                        return PERCENT_REQUIRE;
 
 248   "%right"                          return PERCENT_RIGHT;
 
 249   "%skeleton"                       return PERCENT_SKELETON;
 
 250   "%start"                          return PERCENT_START;
 
 251   "%term"                           return PERCENT_TOKEN;
 
 252   "%token"                          return PERCENT_TOKEN;
 
 253   "%token-table"                    return PERCENT_TOKEN_TABLE;
 
 254   "%type"                           return PERCENT_TYPE;
 
 255   "%union"                          return PERCENT_UNION;
 
 256   "%verbose"                        return PERCENT_VERBOSE;
 
 257   "%yacc"                           return PERCENT_YACC;
 
 260   "%default"[-_]"prec"              DEPRECATED("%default-prec");
 
 261   "%error"[-_]"verbose"             DEPRECATED("%define parse.error verbose");
 
 262   "%expect"[-_]"rr"                 DEPRECATED("%expect-rr");
 
 263   "%file-prefix"{eqopt}             DEPRECATED("%file-prefix");
 
 264   "%fixed"[-_]"output"[-_]"files"   DEPRECATED("%fixed-output-files");
 
 265   "%name"[-_]"prefix"{eqopt}        DEPRECATED("%name-prefix");
 
 266   "%no"[-_]"default"[-_]"prec"      DEPRECATED("%no-default-prec");
 
 267   "%no"[-_]"lines"                  DEPRECATED("%no-lines");
 
 268   "%output"{eqopt}                  DEPRECATED("%output");
 
 269   "%pure"[-_]"parser"               DEPRECATED("%pure-parser");
 
 270   "%token"[-_]"table"               DEPRECATED("%token-table");
 
 273     complain (loc, complaint, _("invalid directive: %s"), quote (yytext));
 
 278   ";"                     return SEMICOLON;
 
 281     val->uniqstr = uniqstr_new (yytext);
 
 283     bracketed_id_str = NULL;
 
 284     BEGIN SC_AFTER_IDENTIFIER;
 
 288     val->integer = scan_integer (yytext, 10, *loc);
 
 291   0[xX][0-9abcdefABCDEF]+ {
 
 292     val->integer = scan_integer (yytext, 16, *loc);
 
 296   /* Identifiers may not start with a digit.  Yet, don't silently
 
 297      accept "1FOO" as "1 FOO".  */
 
 299     complain (loc, complaint, _("invalid identifier: %s"), quote (yytext));
 
 303   "'"         token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
 
 306   "\""        token_start = loc->start; BEGIN SC_ESCAPED_STRING;
 
 309   "%{"        code_start = loc->start; BEGIN SC_PROLOGUE;
 
 311   /* Code in between braces.  */
 
 315     code_start = loc->start;
 
 316     BEGIN SC_BRACED_CODE;
 
 319   /* Semantic predicate. */
 
 320   "%?"[ \f\n\t\v]*"{" {
 
 322     code_start = loc->start;
 
 327   "<*>"       return TAG_ANY;
 
 328   "<>"        return TAG_NONE;
 
 330     obstack_grow (&obstack_for_string, yytext + 1, yyleng - 2);
 
 332     val->uniqstr = uniqstr_new (last_string);
 
 338     token_start = loc->start;
 
 343     static int percent_percent_count;
 
 344     if (++percent_percent_count == 2)
 
 346     return PERCENT_PERCENT;
 
 350     bracketed_id_str = NULL;
 
 351     bracketed_id_start = loc->start;
 
 352     bracketed_id_context_state = YY_START;
 
 353     BEGIN SC_BRACKETED_ID;
 
 357     complain (loc, complaint, _("invalid character: %s"),
 
 358               quote_mem (yytext, yyleng));
 
 362     loc->start = loc->end = scanner_cursor;
 
 368   /*--------------------------------------------------------------.
 
 369   | Supporting \0 complexifies our implementation for no expected |
 
 371   `--------------------------------------------------------------*/
 
 373 <SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING,SC_TAG>
 
 375   \0        complain (loc, complaint, _("invalid null character"));
 
 379   /*-----------------------------------------------------------------.
 
 380   | Scanning after an identifier, checking whether a colon is next.  |
 
 381   `-----------------------------------------------------------------*/
 
 383 <SC_AFTER_IDENTIFIER>
 
 386     if (bracketed_id_str)
 
 388         ROLLBACK_CURRENT_TOKEN;
 
 389         BEGIN SC_RETURN_BRACKETED_ID;
 
 395         bracketed_id_start = loc->start;
 
 396         bracketed_id_context_state = YY_START;
 
 397         BEGIN SC_BRACKETED_ID;
 
 401     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 406     ROLLBACK_CURRENT_TOKEN;
 
 407     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 412     BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
 
 418   /*--------------------------------.
 
 419   | Scanning bracketed identifiers. |
 
 420   `--------------------------------*/
 
 425     if (bracketed_id_str)
 
 427         complain (loc, complaint,
 
 428                   _("unexpected identifier in bracketed name: %s"),
 
 433         bracketed_id_str = uniqstr_new (yytext);
 
 434         bracketed_id_loc = *loc;
 
 438     BEGIN bracketed_id_context_state;
 
 439     if (bracketed_id_str)
 
 441         if (INITIAL == bracketed_id_context_state)
 
 443             val->uniqstr = bracketed_id_str;
 
 444             bracketed_id_str = 0;
 
 445             *loc = bracketed_id_loc;
 
 450       complain (loc, complaint, _("an identifier expected"));
 
 453     complain (loc, complaint, _("invalid character in bracketed name: %s"),
 
 454               quote_mem (yytext, yyleng));
 
 457     BEGIN bracketed_id_context_state;
 
 458     unexpected_eof (bracketed_id_start, "]");
 
 462 <SC_RETURN_BRACKETED_ID>
 
 465     ROLLBACK_CURRENT_TOKEN;
 
 466     val->uniqstr = bracketed_id_str;
 
 467     bracketed_id_str = 0;
 
 468     *loc = bracketed_id_loc;
 
 475   /*---------------------------------------------------------------.
 
 476   | Scanning a Yacc comment.  The initial '/ *' is already eaten.  |
 
 477   `---------------------------------------------------------------*/
 
 481   "*/"     BEGIN context_state;
 
 483   <<EOF>>  unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 487   /*------------------------------------------------------------.
 
 488   | Scanning a C comment.  The initial '/ *' is already eaten.  |
 
 489   `------------------------------------------------------------*/
 
 493   "*"{splice}"/"  STRING_GROW; BEGIN context_state;
 
 494   <<EOF>>         unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 498   /*--------------------------------------------------------------.
 
 499   | Scanning a line comment.  The initial '//' is already eaten.  |
 
 500   `--------------------------------------------------------------*/
 
 504   "\n"           STRING_GROW; BEGIN context_state;
 
 505   {splice}       STRING_GROW;
 
 506   <<EOF>>        BEGIN context_state;
 
 510   /*------------------------------------------------.
 
 511   | Scanning a Bison string, including its escapes. |
 
 512   | The initial quote is already eaten.             |
 
 513   `------------------------------------------------*/
 
 518     if (yytext[0] == '\n')
 
 519       unexpected_newline (token_start, "\"");
 
 521     loc->start = token_start;
 
 522     val->chars = last_string;
 
 527     unexpected_eof (token_start, "\"");
 
 529     loc->start = token_start;
 
 530     val->chars = last_string;
 
 536   /*----------------------------------------------------------.
 
 537   | Scanning a Bison character literal, decoding its escapes. |
 
 538   | The initial quote is already eaten.                       |
 
 539   `----------------------------------------------------------*/
 
 541 <SC_ESCAPED_CHARACTER>
 
 545     loc->start = token_start;
 
 546     val->character = last_string[0];
 
 548       /* FIXME: Eventually, make these errors.  */
 
 549       if (last_string[0] == '\0')
 
 551           complain (loc, Wother, _("empty character literal"));
 
 552           /* '\0' seems dangerous even if we are about to complain.  */
 
 553           val->character = '\'';
 
 555       else if (last_string[1] != '\0')
 
 556         complain (loc, Wother,
 
 557                   _("extra characters in character literal"));
 
 559     if (yytext[0] == '\n')
 
 560       unexpected_newline (token_start, "'");
 
 567     loc->start = token_start;
 
 568     val->character = last_string[0];
 
 570       /* FIXME: Eventually, make these errors.  */
 
 571       if (last_string[0] == '\0')
 
 573           complain (loc, Wother, _("empty character literal"));
 
 574           /* '\0' seems dangerous even if we are about to complain.  */
 
 575           val->character = '\'';
 
 577       else if (last_string[1] != '\0')
 
 578         complain (loc, Wother,
 
 579                   _("extra characters in character literal"));
 
 581     unexpected_eof (token_start, "'");
 
 588   /*-----------------------------------------------------------.
 
 589   | Scanning a Bison nested tag.  The initial angle bracket is |
 
 591   `-----------------------------------------------------------*/
 
 600         loc->start = token_start;
 
 601         val->uniqstr = uniqstr_new (last_string);
 
 610   "<"+   STRING_GROW; nesting += yyleng;
 
 613     unexpected_eof (token_start, ">");
 
 615     loc->start = token_start;
 
 616     val->uniqstr = uniqstr_new (last_string);
 
 623   /*----------------------------.
 
 624   | Decode escaped characters.  |
 
 625   `----------------------------*/
 
 627 <SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
 
 630     unsigned long int c = strtoul (yytext + 1, NULL, 8);
 
 631     if (!c || UCHAR_MAX < c)
 
 632       complain (loc, complaint, _("invalid number after \\-escape: %s"),
 
 635       obstack_1grow (&obstack_for_string, c);
 
 638   \\x[0-9abcdefABCDEF]+ {
 
 639     verify (UCHAR_MAX < ULONG_MAX);
 
 640     unsigned long int c = strtoul (yytext + 2, NULL, 16);
 
 641     if (!c || UCHAR_MAX < c)
 
 642       complain (loc, complaint, _("invalid number after \\-escape: %s"),
 
 645       obstack_1grow (&obstack_for_string, c);
 
 648   \\a   obstack_1grow (&obstack_for_string, '\a');
 
 649   \\b   obstack_1grow (&obstack_for_string, '\b');
 
 650   \\f   obstack_1grow (&obstack_for_string, '\f');
 
 651   \\n   obstack_1grow (&obstack_for_string, '\n');
 
 652   \\r   obstack_1grow (&obstack_for_string, '\r');
 
 653   \\t   obstack_1grow (&obstack_for_string, '\t');
 
 654   \\v   obstack_1grow (&obstack_for_string, '\v');
 
 656   /* \\[\"\'?\\] would be shorter, but it confuses xgettext.  */
 
 657   \\("\""|"'"|"?"|"\\")  obstack_1grow (&obstack_for_string, yytext[1]);
 
 659   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
 
 660     int c = convert_ucn_to_byte (yytext);
 
 662       complain (loc, complaint, _("invalid number after \\-escape: %s"),
 
 665       obstack_1grow (&obstack_for_string, c);
 
 668     char const *p = yytext + 1;
 
 669     /* Quote only if escaping won't make the character visible.  */
 
 670     if (c_isspace ((unsigned char) *p) && c_isprint ((unsigned char) *p))
 
 673       p = quotearg_style_mem (escape_quoting_style, p, 1);
 
 674     complain (loc, complaint, _("invalid character after \\-escape: %s"),
 
 679   /*--------------------------------------------.
 
 680   | Scanning user-code characters and strings.  |
 
 681   `--------------------------------------------*/
 
 683 <SC_CHARACTER,SC_STRING>
 
 685   {splice}|\\{splice}[^\n\[\]]  STRING_GROW;
 
 690   "'"           STRING_GROW; BEGIN context_state;
 
 691   \n            unexpected_newline (token_start, "'"); BEGIN context_state;
 
 692   <<EOF>>       unexpected_eof (token_start, "'"); BEGIN context_state;
 
 697   "\""          STRING_GROW; BEGIN context_state;
 
 698   \n            unexpected_newline (token_start, "\""); BEGIN context_state;
 
 699   <<EOF>>       unexpected_eof (token_start, "\""); BEGIN context_state;
 
 703   /*---------------------------------------------------.
 
 704   | Strings, comments etc. can be found in user code.  |
 
 705   `---------------------------------------------------*/
 
 707 <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_PREDICATE>
 
 711     context_state = YY_START;
 
 712     token_start = loc->start;
 
 717     context_state = YY_START;
 
 718     token_start = loc->start;
 
 723     context_state = YY_START;
 
 724     token_start = loc->start;
 
 729     context_state = YY_START;
 
 730     BEGIN SC_LINE_COMMENT;
 
 736   /*-----------------------------------------------------------.
 
 737   | Scanning some code in braces (actions, predicates). The    |
 
 738   | initial "{" is already eaten.                              |
 
 739   `-----------------------------------------------------------*/
 
 741 <SC_BRACED_CODE,SC_PREDICATE>
 
 743   "{"|"<"{splice}"%"  STRING_GROW; nesting++;
 
 744   "%"{splice}">"      STRING_GROW; nesting--;
 
 746   /* Tokenize '<<%' correctly (as '<<' '%') rather than incorrrectly
 
 748   "<"{splice}"<"  STRING_GROW;
 
 751     int token = (YY_START == SC_BRACED_CODE) ? BRACED_CODE : BRACED_PREDICATE;
 
 752     unexpected_eof (code_start, "}");
 
 754     loc->start = code_start;
 
 755     val->code = last_string;
 
 764     obstack_1grow (&obstack_for_string, '}');
 
 770         loc->start = code_start;
 
 771         val->code = last_string;
 
 785         loc->start = code_start;
 
 786         val->code = last_string;
 
 788         return BRACED_PREDICATE;
 
 791       obstack_1grow (&obstack_for_string, '}');
 
 795   /*--------------------------------------------------------------.
 
 796   | Scanning some prologue: from "%{" (already scanned) to "%}".  |
 
 797   `--------------------------------------------------------------*/
 
 803     loc->start = code_start;
 
 804     val->chars = last_string;
 
 810     unexpected_eof (code_start, "%}");
 
 812     loc->start = code_start;
 
 813     val->chars = last_string;
 
 820   /*---------------------------------------------------------------.
 
 821   | Scanning the epilogue (everything after the second "%%", which |
 
 822   | has already been eaten).                                       |
 
 823   `---------------------------------------------------------------*/
 
 829     loc->start = code_start;
 
 830     val->chars = last_string;
 
 837   /*-----------------------------------------------------.
 
 838   | By default, grow the string obstack with the input.  |
 
 839   `-----------------------------------------------------*/
 
 841 <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>. |
 
 842   <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE>\n    STRING_GROW;
 
 846 /* Read bytes from FP into buffer BUF of size SIZE.  Return the
 
 847    number of bytes read.  Remove '\r' from input, treating \r\n
 
 848    and isolated \r as \n.  */
 
 851 no_cr_read (FILE *fp, char *buf, size_t size)
 
 853   size_t bytes_read = fread (buf, 1, size, fp);
 
 856       char *w = memchr (buf, '\r', bytes_read);
 
 860           char const *lim = buf + bytes_read;
 
 864               /* Found an '\r'.  Treat it like '\n', but ignore any
 
 865                  '\n' that immediately follows.  */
 
 870                   if (ch != '\n' && ungetc (ch, fp) != ch)
 
 876               /* Copy until the next '\r'.  */
 
 882               while ((*w++ = *r++) != '\r');
 
 894 /*------------------------------------------------------.
 
 895 | Scan NUMBER for a base-BASE integer at location LOC.  |
 
 896 `------------------------------------------------------*/
 
 898 static unsigned long int
 
 899 scan_integer (char const *number, int base, location loc)
 
 901   verify (INT_MAX < ULONG_MAX);
 
 902   unsigned long int num = strtoul (number, NULL, base);
 
 906       complain (&loc, complaint, _("integer out of range: %s"),
 
 915 /*------------------------------------------------------------------.
 
 916 | Convert universal character name UCN to a single-byte character,  |
 
 917 | and return that character.  Return -1 if UCN does not correspond  |
 
 918 | to a single-byte character.                                       |
 
 919 `------------------------------------------------------------------*/
 
 922 convert_ucn_to_byte (char const *ucn)
 
 924   verify (UCHAR_MAX <= INT_MAX);
 
 925   unsigned long int code = strtoul (ucn + 2, NULL, 16);
 
 927   /* FIXME: Currently we assume Unicode-compatible unibyte characters
 
 928      on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes).  On
 
 929      non-ASCII hosts we support only the portable C character set.
 
 930      These limitations should be removed once we add support for
 
 931      multibyte characters.  */
 
 933   if (UCHAR_MAX < code)
 
 936 #if ! ('$' == 0x24 && '@' == 0x40 && '`' == 0x60 && '~' == 0x7e)
 
 938     /* A non-ASCII host.  Use CODE to index into a table of the C
 
 939        basic execution character set, which is guaranteed to exist on
 
 940        all Standard C platforms.  This table also includes '$', '@',
 
 941        and '`', which are not in the basic execution character set but
 
 942        which are unibyte characters on all the platforms that we know
 
 944     static signed char const table[] =
 
 946         '\0',   -1,   -1,   -1,   -1,   -1,   -1, '\a',
 
 947         '\b', '\t', '\n', '\v', '\f', '\r',   -1,   -1,
 
 948           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 949           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 950          ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
 
 951          '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
 
 952          '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
 
 953          '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
 
 954          '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',
 
 955          'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
 
 956          'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
 
 957          'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_',
 
 958          '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
 
 959          'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
 
 960          'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
 
 961          'x',  'y',  'z',  '{',  '|',  '}',  '~'
 
 964     code = code < sizeof table ? table[code] : -1;
 
 972 /*----------------------------------------------------------------.
 
 973 | Handle '#line INT "FILE"'.  ARGS has already skipped '#line '.  |
 
 974 `----------------------------------------------------------------*/
 
 977 handle_syncline (char *args, location loc)
 
 980   unsigned long int lineno = strtoul (args, &after_num, 10);
 
 981   char *file = strchr (after_num, '"') + 1;
 
 982   *strchr (file, '"') = '\0';
 
 983   if (INT_MAX <= lineno)
 
 985       complain (&loc, Wother, _("line number overflow"));
 
 988   current_file = uniqstr_new (file);
 
 989   boundary_set (&scanner_cursor, current_file, lineno, 1);
 
 993 /*----------------------------------------------------------------.
 
 994 | For a token or comment starting at START, report message MSGID, |
 
 995 | which should say that an end marker was found before            |
 
 996 | the expected TOKEN_END.                                         |
 
 997 `----------------------------------------------------------------*/
 
1000 unexpected_end (boundary start, char const *msgid, char const *token_end)
 
1004   loc.end = scanner_cursor;
 
1005   token_end = quote (token_end);
 
1006   // Instead of '\'', display "'".
 
1007   if (STREQ (token_end, "'\\''"))
 
1008     token_end = "\"'\"";
 
1009   complain (&loc, complaint, _(msgid), token_end);
 
1013 /*------------------------------------------------------------------------.
 
1014 | Report an unexpected EOF in a token or comment starting at START.       |
 
1015 | An end of file was encountered and the expected TOKEN_END was missing.  |
 
1016 `------------------------------------------------------------------------*/
 
1019 unexpected_eof (boundary start, char const *token_end)
 
1021   unexpected_end (start, N_("missing %s at end of file"), token_end);
 
1025 /*----------------------------------------.
 
1026 | Likewise, but for unexpected newlines.  |
 
1027 `----------------------------------------*/
 
1030 unexpected_newline (boundary start, char const *token_end)
 
1032   unexpected_end (start, N_("missing %s at end of line"), token_end);
 
1036 /*-------------------------.
 
1037 | Initialize the scanner.  |
 
1038 `-------------------------*/
 
1041 gram_scanner_initialize (void)
 
1043   obstack_init (&obstack_for_string);
 
1047 /*-----------------------------------------------.
 
1048 | Free all the memory allocated to the scanner.  |
 
1049 `-----------------------------------------------*/
 
1052 gram_scanner_free (void)
 
1054   obstack_free (&obstack_for_string, 0);
 
1055   /* Reclaim Flex's buffers.  */