1 /* Bison Grammar Scanner                             -*- C -*-
 
   3    Copyright (C) 2002, 2003 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 2 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, write to the Free Software
 
  19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 
  23 %option debug nodefault nounput noyywrap never-interactive
 
  24 %option prefix="gram_" outfile="lex.yy.c"
 
  30 #include <get-errno.h>
 
  40 #define YY_USER_INIT                                    \
 
  43       scanner_cursor.file = current_file;               \
 
  44       scanner_cursor.line = 1;                          \
 
  45       scanner_cursor.column = 1;                        \
 
  46       code_start = scanner_cursor;                      \
 
  50 /* Location of scanner cursor.  */
 
  51 boundary scanner_cursor;
 
  53 static void adjust_location (location *, char const *, size_t);
 
  54 #define YY_USER_ACTION  adjust_location (loc, 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))
 
  60 /* OBSTACK_FOR_STRING -- Used to store all the characters that we need to
 
  61    keep (to construct ID, STRINGS etc.).  Use the following macros to
 
  64    Use STRING_GROW to append what has just been matched, and
 
  65    STRING_FINISH to end the string (it puts the ending 0).
 
  66    STRING_FINISH also stores this string in LAST_STRING, which can be
 
  67    used, and which is used by STRING_FREE to free the last string.  */
 
  69 static struct obstack obstack_for_string;
 
  71 /* A string representing the most recently saved token.  */
 
  72 static char *last_string;
 
  76   obstack_grow (&obstack_for_string, yytext, yyleng)
 
  78 #define STRING_FINISH                                   \
 
  80     obstack_1grow (&obstack_for_string, '\0');          \
 
  81     last_string = obstack_finish (&obstack_for_string); \
 
  85   obstack_free (&obstack_for_string, last_string)
 
  88 scanner_last_string_free (void)
 
  93 /* Within well-formed rules, RULE_LENGTH is the number of values in
 
  94    the current rule so far, which says where to find `$0' with respect
 
  95    to the top of the stack.  It is not the same as the rule->length in
 
  96    the case of mid rule actions.
 
  98    Outside of well-formed rules, RULE_LENGTH has an undefined value.  */
 
  99 static int rule_length;
 
 101 static void handle_dollar (int token_type, char *cp, location loc);
 
 102 static void handle_at (int token_type, char *cp, location loc);
 
 103 static void handle_syncline (char *args);
 
 104 static int convert_ucn_to_byte (char const *hex_text);
 
 105 static void unexpected_eof (boundary, char const *);
 
 108 %x SC_COMMENT SC_LINE_COMMENT SC_YACC_COMMENT
 
 109 %x SC_STRING SC_CHARACTER
 
 110 %x SC_AFTER_IDENTIFIER
 
 111 %x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
 
 112 %x SC_PRE_CODE SC_BRACED_CODE SC_PROLOGUE SC_EPILOGUE
 
 114 letter    [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
 
 115 id        {letter}({letter}|[0-9])*
 
 116 directive %{letter}({letter}|[0-9]|-)*
 
 119 /* POSIX says that a tag must be both an id and a C union member, but
 
 120    historically almost any character is allowed in a tag.  We disallow
 
 121    NUL and newline, as this simplifies our implementation.  */
 
 124 /* Zero or more instances of backslash-newline.  Following GCC, allow
 
 125    white space between the backslash and the newline.  */
 
 126 splice   (\\[ \f\t\v]*\n)*
 
 130   /* Nesting level of the current code in braces.  */
 
 131   int braces_level IF_LINT (= 0);
 
 133   /* Parent context state, when applicable.  */
 
 134   int context_state IF_LINT (= 0);
 
 136   /* Token type to return, when applicable.  */
 
 137   int token_type IF_LINT (= 0);
 
 139   /* Location of most recent identifier, when applicable.  */
 
 140   location id_loc IF_LINT (= empty_location);
 
 142   /* Where containing code started, when applicable.  Its initial
 
 143      value is relevant only when yylex is invoked in the SC_EPILOGUE
 
 145   boundary code_start = scanner_cursor;
 
 147   /* Where containing comment or string or character literal started,
 
 149   boundary token_start IF_LINT (= scanner_cursor);
 
 153   /*-----------------------.
 
 154   | Scanning white space.  |
 
 155   `-----------------------*/
 
 157 <INITIAL,SC_AFTER_IDENTIFIER,SC_PRE_CODE>
 
 160   ","          warn_at (*loc, _("stray `,' treated as white space"));
 
 165     token_start = loc->start;
 
 166     context_state = YY_START;
 
 167     BEGIN SC_YACC_COMMENT;
 
 170   /* #line directives are not documented, and may be withdrawn or
 
 171      modified in future versions of Bison.  */
 
 172   ^"#line "{int}" \"".*"\"\n" {
 
 173     handle_syncline (yytext + sizeof "#line " - 1);
 
 178   /*----------------------------.
 
 179   | Scanning Bison directives.  |
 
 180   `----------------------------*/
 
 183   "%binary"               return PERCENT_NONASSOC;
 
 184   "%debug"                return PERCENT_DEBUG;
 
 185   "%default"[-_]"prec"    return PERCENT_DEFAULT_PREC;
 
 186   "%define"               return PERCENT_DEFINE;
 
 187   "%defines"              return PERCENT_DEFINES;
 
 188   "%destructor"           token_type = PERCENT_DESTRUCTOR; BEGIN SC_PRE_CODE;
 
 189   "%dprec"                return PERCENT_DPREC;
 
 190   "%error"[-_]"verbose"   return PERCENT_ERROR_VERBOSE;
 
 191   "%expect"               return PERCENT_EXPECT;
 
 192   "%file-prefix"          return PERCENT_FILE_PREFIX;
 
 193   "%fixed"[-_]"output"[-_]"files"   return PERCENT_YACC;
 
 194   "%initial-action"       token_type = PERCENT_INITIAL_ACTION; BEGIN SC_PRE_CODE;
 
 195   "%glr-parser"           return PERCENT_GLR_PARSER;
 
 196   "%left"                 return PERCENT_LEFT;
 
 197   "%lex-param"            token_type = PERCENT_LEX_PARAM; BEGIN SC_PRE_CODE;
 
 198   "%locations"            return PERCENT_LOCATIONS;
 
 199   "%merge"                return PERCENT_MERGE;
 
 200   "%name"[-_]"prefix"     return PERCENT_NAME_PREFIX;
 
 201   "%no"[-_]"default"[-_]"prec"  return PERCENT_NO_DEFAULT_PREC;
 
 202   "%no"[-_]"lines"        return PERCENT_NO_LINES;
 
 203   "%nonassoc"             return PERCENT_NONASSOC;
 
 204   "%nondeterministic-parser"   return PERCENT_NONDETERMINISTIC_PARSER;
 
 205   "%nterm"                return PERCENT_NTERM;
 
 206   "%output"               return PERCENT_OUTPUT;
 
 207   "%parse-param"          token_type = PERCENT_PARSE_PARAM; BEGIN SC_PRE_CODE;
 
 208   "%prec"                 rule_length--; return PERCENT_PREC;
 
 209   "%printer"              token_type = PERCENT_PRINTER; BEGIN SC_PRE_CODE;
 
 210   "%pure"[-_]"parser"     return PERCENT_PURE_PARSER;
 
 211   "%right"                return PERCENT_RIGHT;
 
 212   "%skeleton"             return PERCENT_SKELETON;
 
 213   "%start"                return PERCENT_START;
 
 214   "%term"                 return PERCENT_TOKEN;
 
 215   "%token"                return PERCENT_TOKEN;
 
 216   "%token"[-_]"table"     return PERCENT_TOKEN_TABLE;
 
 217   "%type"                 return PERCENT_TYPE;
 
 218   "%union"                token_type = PERCENT_UNION; BEGIN SC_PRE_CODE;
 
 219   "%verbose"              return PERCENT_VERBOSE;
 
 220   "%yacc"                 return PERCENT_YACC;
 
 223     complain_at (*loc, _("invalid directive: %s"), quote (yytext));
 
 227   "|"                     rule_length = 0; return PIPE;
 
 228   ";"                     return SEMICOLON;
 
 231     val->symbol = symbol_get (yytext, *loc);
 
 234     BEGIN SC_AFTER_IDENTIFIER;
 
 240     num = strtoul (yytext, 0, 10);
 
 241     if (INT_MAX < num || get_errno ())
 
 243         complain_at (*loc, _("integer out of range: %s"), quote (yytext));
 
 250   /* Characters.  We don't check there is only one.  */
 
 251   "'"         STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
 
 254   "\""        STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_STRING;
 
 257   "%{"        code_start = loc->start; BEGIN SC_PROLOGUE;
 
 259   /* Code in between braces.  */
 
 262     token_type = BRACED_CODE;
 
 264     code_start = loc->start;
 
 265     BEGIN SC_BRACED_CODE;
 
 270     obstack_grow (&obstack_for_string, yytext + 1, yyleng - 2);
 
 272     val->uniqstr = uniqstr_new (last_string);
 
 278     static int percent_percent_count;
 
 279     if (++percent_percent_count == 2)
 
 281     return PERCENT_PERCENT;
 
 285     complain_at (*loc, _("invalid character: %s"), quote (yytext));
 
 289     loc->start = loc->end = scanner_cursor;
 
 295   /*-----------------------------------------------------------------.
 
 296   | Scanning after an identifier, checking whether a colon is next.  |
 
 297   `-----------------------------------------------------------------*/
 
 299 <SC_AFTER_IDENTIFIER>
 
 308     scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);
 
 322   /*---------------------------------------------------------------.
 
 323   | Scanning a Yacc comment.  The initial `/ *' is already eaten.  |
 
 324   `---------------------------------------------------------------*/
 
 328   "*/"     BEGIN context_state;
 
 330   <<EOF>>  unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 334   /*------------------------------------------------------------.
 
 335   | Scanning a C comment.  The initial `/ *' is already eaten.  |
 
 336   `------------------------------------------------------------*/
 
 340   "*"{splice}"/"  STRING_GROW; BEGIN context_state;
 
 341   <<EOF>>         unexpected_eof (token_start, "*/"); BEGIN context_state;
 
 345   /*--------------------------------------------------------------.
 
 346   | Scanning a line comment.  The initial `//' is already eaten.  |
 
 347   `--------------------------------------------------------------*/
 
 351   "\n"           STRING_GROW; BEGIN context_state;
 
 352   {splice}       STRING_GROW;
 
 353   <<EOF>>        BEGIN context_state;
 
 357   /*----------------------------------------------------------------.
 
 358   | Scanning a C string, including its escapes.  The initial `"' is |
 
 360   `----------------------------------------------------------------*/
 
 367     loc->start = token_start;
 
 368     val->chars = last_string;
 
 374   \0        complain_at (*loc, _("invalid null character"));
 
 376   <<EOF>>   unexpected_eof (token_start, "\""); BEGIN INITIAL;
 
 379   /*---------------------------------------------------------------.
 
 380   | Scanning a C character, decoding its escapes.  The initial "'" |
 
 381   | is already eaten.                                              |
 
 382   `---------------------------------------------------------------*/
 
 384 <SC_ESCAPED_CHARACTER>
 
 387     unsigned char last_string_1;
 
 390     loc->start = token_start;
 
 391     val->symbol = symbol_get (last_string, *loc);
 
 392     symbol_class_set (val->symbol, token_sym, *loc);
 
 393     last_string_1 = last_string[1];
 
 394     symbol_user_token_number_set (val->symbol, last_string_1, *loc);
 
 401   \0        complain_at (*loc, _("invalid null character"));
 
 403   <<EOF>>   unexpected_eof (token_start, "'"); BEGIN INITIAL;
 
 407   /*----------------------------.
 
 408   | Decode escaped characters.  |
 
 409   `----------------------------*/
 
 411 <SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
 
 414     unsigned long c = strtoul (yytext + 1, 0, 8);
 
 416       complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
 
 418       complain_at (*loc, _("invalid null character: %s"), quote (yytext));
 
 420       obstack_1grow (&obstack_for_string, c);
 
 423   \\x[0-9abcdefABCDEF]+ {
 
 426     c = strtoul (yytext + 2, 0, 16);
 
 427     if (UCHAR_MAX < c || get_errno ())
 
 428       complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
 
 430       complain_at (*loc, _("invalid null character: %s"), quote (yytext));
 
 432       obstack_1grow (&obstack_for_string, c);
 
 435   \\a   obstack_1grow (&obstack_for_string, '\a');
 
 436   \\b   obstack_1grow (&obstack_for_string, '\b');
 
 437   \\f   obstack_1grow (&obstack_for_string, '\f');
 
 438   \\n   obstack_1grow (&obstack_for_string, '\n');
 
 439   \\r   obstack_1grow (&obstack_for_string, '\r');
 
 440   \\t   obstack_1grow (&obstack_for_string, '\t');
 
 441   \\v   obstack_1grow (&obstack_for_string, '\v');
 
 443   /* \\[\"\'?\\] would be shorter, but it confuses xgettext.  */
 
 444   \\("\""|"'"|"?"|"\\")  obstack_1grow (&obstack_for_string, yytext[1]);
 
 446   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
 
 447     int c = convert_ucn_to_byte (yytext);
 
 449       complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
 
 451       complain_at (*loc, _("invalid null character: %s"), quote (yytext));
 
 453       obstack_1grow (&obstack_for_string, c);
 
 456     complain_at (*loc, _("unrecognized escape sequence: %s"), quote (yytext));
 
 462   /*----------------------------------------------------------.
 
 463   | Scanning a C character without decoding its escapes.  The |
 
 464   | initial "'" is already eaten.                             |
 
 465   `----------------------------------------------------------*/
 
 469   "'"                   STRING_GROW; BEGIN context_state;
 
 470   \\{splice}[^$@\[\]]   STRING_GROW;
 
 471   <<EOF>>               unexpected_eof (token_start, "'"); BEGIN context_state;
 
 475   /*----------------------------------------------------------------.
 
 476   | Scanning a C string, without decoding its escapes.  The initial |
 
 477   | `"' is already eaten.                                           |
 
 478   `----------------------------------------------------------------*/
 
 482   "\""                  STRING_GROW; BEGIN context_state;
 
 483   \\{splice}[^$@\[\]]   STRING_GROW;
 
 485     unexpected_eof (token_start, "\"");
 
 491   /*---------------------------------------------------.
 
 492   | Strings, comments etc. can be found in user code.  |
 
 493   `---------------------------------------------------*/
 
 495 <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
 
 499     context_state = YY_START;
 
 500     token_start = loc->start;
 
 505     context_state = YY_START;
 
 506     token_start = loc->start;
 
 511     context_state = YY_START;
 
 512     token_start = loc->start;
 
 517     context_state = YY_START;
 
 518     BEGIN SC_LINE_COMMENT;
 
 523   /*---------------------------------------------------------------.
 
 524   | Scanning after %union etc., possibly followed by white space.  |
 
 525   | For %union only, allow arbitrary C code to appear before the   |
 
 526   | following brace, as an extension to POSIX.                     |
 
 527   `---------------------------------------------------------------*/
 
 532     bool valid = yytext[0] == '{' || token_type == PERCENT_UNION;
 
 533     scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);
 
 539         code_start = loc->start;
 
 540         BEGIN SC_BRACED_CODE;
 
 544         complain_at (*loc, _("missing `{' in `%s'"),
 
 545                      token_name (token_type));
 
 546         obstack_sgrow (&obstack_for_string, "{}");
 
 548         val->chars = last_string;
 
 554   <<EOF>>  unexpected_eof (scanner_cursor, "{}"); BEGIN INITIAL;
 
 558   /*---------------------------------------------------------------.
 
 559   | Scanning some code in braces (%union and actions). The initial |
 
 560   | "{" is already eaten.                                          |
 
 561   `---------------------------------------------------------------*/
 
 565   "{"|"<"{splice}"%"  STRING_GROW; braces_level++;
 
 566   "%"{splice}">"      STRING_GROW; braces_level--;
 
 568     bool outer_brace = --braces_level < 0;
 
 570     /* As an undocumented Bison extension, append `;' before the last
 
 571        brace in braced code, so that the user code can omit trailing
 
 572        `;'.  But do not append `;' if emulating Yacc, since Yacc does
 
 575        FIXME: Bison should warn if a semicolon seems to be necessary
 
 576        here, and should omit the semicolon if it seems unnecessary
 
 577        (e.g., after ';', '{', or '}', each followed by comments or
 
 578        white space).  Such a warning shouldn't depend on --yacc; it
 
 579        should depend on a new --pedantic option, which would cause
 
 580        Bison to warn if it detects an extension to POSIX.  --pedantic
 
 581        should also diagnose other Bison extensions like %yacc.
 
 582        Perhaps there should also be a GCC-style --pedantic-errors
 
 583        option, so that such warnings are diagnosed as errors.  */
 
 584     if (outer_brace && token_type == BRACED_CODE && ! yacc_flag)
 
 585       obstack_1grow (&obstack_for_string, ';');
 
 587     obstack_1grow (&obstack_for_string, '}');
 
 593         loc->start = code_start;
 
 594         val->chars = last_string;
 
 600   /* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
 
 602   "<"{splice}"<"  STRING_GROW;
 
 604   "$"("<"{tag}">")?(-?[0-9]+|"$")  handle_dollar (token_type, yytext, *loc);
 
 605   "@"(-?[0-9]+|"$")                handle_at (token_type, yytext, *loc);
 
 607   <<EOF>>  unexpected_eof (code_start, "}"); BEGIN INITIAL;
 
 611   /*--------------------------------------------------------------.
 
 612   | Scanning some prologue: from "%{" (already scanned) to "%}".  |
 
 613   `--------------------------------------------------------------*/
 
 619     loc->start = code_start;
 
 620     val->chars = last_string;
 
 625   <<EOF>>  unexpected_eof (code_start, "%}"); BEGIN INITIAL;
 
 629   /*---------------------------------------------------------------.
 
 630   | Scanning the epilogue (everything after the second "%%", which |
 
 631   | has already been eaten).                                       |
 
 632   `---------------------------------------------------------------*/
 
 638     loc->start = code_start;
 
 639     val->chars = last_string;
 
 646   /*----------------------------------------------------------------.
 
 647   | By default, grow the string obstack with the input, escaping M4 |
 
 648   | quoting characters.                                             |
 
 649   `----------------------------------------------------------------*/
 
 651 <SC_COMMENT,SC_LINE_COMMENT,SC_STRING,SC_CHARACTER,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
 
 653   \$    obstack_sgrow (&obstack_for_string, "$][");
 
 654   \@    obstack_sgrow (&obstack_for_string, "@@");
 
 655   \[    obstack_sgrow (&obstack_for_string, "@{");
 
 656   \]    obstack_sgrow (&obstack_for_string, "@}");
 
 663 /* Keeps track of the maximum number of semantic values to the left of
 
 664    a handle (those referenced by $0, $-1, etc.) are required by the
 
 665    semantic actions of this grammar. */
 
 666 int max_left_semantic_context = 0;
 
 668 /* Set *LOC and adjust scanner cursor to account for token TOKEN of
 
 672 adjust_location (location *loc, char const *token, size_t size)
 
 674   int line = scanner_cursor.line;
 
 675   int column = scanner_cursor.column;
 
 676   char const *p0 = token;
 
 677   char const *p = token;
 
 678   char const *lim = token + size;
 
 680   loc->start = scanner_cursor;
 
 682   for (p = token; p < lim; p++)
 
 692         column += mbsnwidth (p0, p - p0, 0);
 
 693         column += 8 - ((column - 1) & 7);
 
 698   scanner_cursor.line = line;
 
 699   scanner_cursor.column = column + mbsnwidth (p0, p - p0, 0);
 
 701   loc->end = scanner_cursor;
 
 705 /* Read bytes from FP into buffer BUF of size SIZE.  Return the
 
 706    number of bytes read.  Remove '\r' from input, treating \r\n
 
 707    and isolated \r as \n.  */
 
 710 no_cr_read (FILE *fp, char *buf, size_t size)
 
 712   size_t bytes_read = fread (buf, 1, size, fp);
 
 715       char *w = memchr (buf, '\r', bytes_read);
 
 719           char const *lim = buf + bytes_read;
 
 723               /* Found an '\r'.  Treat it like '\n', but ignore any
 
 724                  '\n' that immediately follows.  */
 
 729                   if (ch != '\n' && ungetc (ch, fp) != ch)
 
 735               /* Copy until the next '\r'.  */
 
 741               while ((*w++ = *r++) != '\r');
 
 752 /*------------------------------------------------------------------.
 
 753 | TEXT is pointing to a wannabee semantic value (i.e., a `$').      |
 
 755 | Possible inputs: $[<TYPENAME>]($|integer)                         |
 
 757 | Output to OBSTACK_FOR_STRING a reference to this semantic value.  |
 
 758 `------------------------------------------------------------------*/
 
 761 handle_action_dollar (char *text, location loc)
 
 763   const char *type_name = NULL;
 
 769   /* Get the type name if explicit. */
 
 782         type_name = symbol_list_n_type_name_get (current_rule, loc, 0);
 
 783       if (!type_name && typed)
 
 784         complain_at (loc, _("$$ of `%s' has no declared type"),
 
 785                      current_rule->sym->tag);
 
 788       obstack_fgrow1 (&obstack_for_string,
 
 789                       "]b4_lhs_value([%s])[", type_name);
 
 795       num = strtol (cp, 0, 10);
 
 797       if (INT_MIN <= num && num <= rule_length && ! get_errno ())
 
 800           if (1-n > max_left_semantic_context)
 
 801             max_left_semantic_context = 1-n;
 
 802           if (!type_name && n > 0)
 
 803             type_name = symbol_list_n_type_name_get (current_rule, loc, n);
 
 804           if (!type_name && typed)
 
 805             complain_at (loc, _("$%d of `%s' has no declared type"),
 
 806                          n, current_rule->sym->tag);
 
 809           obstack_fgrow3 (&obstack_for_string,
 
 810                           "]b4_rhs_value([%d], [%d], [%s])[",
 
 811                           rule_length, n, type_name);
 
 814         complain_at (loc, _("integer out of range: %s"), quote (text));
 
 821 /*----------------------------------------------------------------.
 
 822 | Map `$?' onto the proper M4 symbol, depending on its TOKEN_TYPE |
 
 823 | (are we in an action?).                                         |
 
 824 `----------------------------------------------------------------*/
 
 827 handle_dollar (int token_type, char *text, location loc)
 
 832       if (handle_action_dollar (text, loc))
 
 836     case PERCENT_DESTRUCTOR:
 
 837     case PERCENT_INITIAL_ACTION:
 
 838     case PERCENT_PRINTER:
 
 841           obstack_sgrow (&obstack_for_string, "]b4_dollar_dollar[");
 
 850   complain_at (loc, _("invalid value: %s"), quote (text));
 
 854 /*------------------------------------------------------.
 
 855 | TEXT is a location token (i.e., a `@...').  Output to |
 
 856 | OBSTACK_FOR_STRING a reference to this location.      |
 
 857 `------------------------------------------------------*/
 
 860 handle_action_at (char *text, location loc)
 
 863   locations_flag = true;
 
 869     obstack_sgrow (&obstack_for_string, "]b4_lhs_location[");
 
 874       num = strtol (cp, 0, 10);
 
 876       if (INT_MIN <= num && num <= rule_length && ! get_errno ())
 
 879           obstack_fgrow2 (&obstack_for_string, "]b4_rhs_location([%d], [%d])[",
 
 883         complain_at (loc, _("integer out of range: %s"), quote (text));
 
 890 /*----------------------------------------------------------------.
 
 891 | Map `@?' onto the proper M4 symbol, depending on its TOKEN_TYPE |
 
 892 | (are we in an action?).                                         |
 
 893 `----------------------------------------------------------------*/
 
 896 handle_at (int token_type, char *text, location loc)
 
 901       handle_action_at (text, loc);
 
 904     case PERCENT_INITIAL_ACTION:
 
 905     case PERCENT_DESTRUCTOR:
 
 906     case PERCENT_PRINTER:
 
 909           obstack_sgrow (&obstack_for_string, "]b4_at_dollar[");
 
 918   complain_at (loc, _("invalid value: %s"), quote (text));
 
 922 /*------------------------------------------------------------------.
 
 923 | Convert universal character name UCN to a single-byte character,  |
 
 924 | and return that character.  Return -1 if UCN does not correspond  |
 
 925 | to a single-byte character.                                       |
 
 926 `------------------------------------------------------------------*/
 
 929 convert_ucn_to_byte (char const *ucn)
 
 931   unsigned long code = strtoul (ucn + 2, 0, 16);
 
 933   /* FIXME: Currently we assume Unicode-compatible unibyte characters
 
 934      on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes).  On
 
 935      non-ASCII hosts we support only the portable C character set.
 
 936      These limitations should be removed once we add support for
 
 937      multibyte characters.  */
 
 939   if (UCHAR_MAX < code)
 
 942 #if ! ('$' == 0x24 && '@' == 0x40 && '`' == 0x60 && '~' == 0x7e)
 
 944     /* A non-ASCII host.  Use CODE to index into a table of the C
 
 945        basic execution character set, which is guaranteed to exist on
 
 946        all Standard C platforms.  This table also includes '$', '@',
 
 947        and '`', which are not in the basic execution character set but
 
 948        which are unibyte characters on all the platforms that we know
 
 950     static signed char const table[] =
 
 952         '\0',   -1,   -1,   -1,   -1,   -1,   -1, '\a',
 
 953         '\b', '\t', '\n', '\v', '\f', '\r',   -1,   -1,
 
 954           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 955           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
 
 956          ' ',  '!',  '"',  '#',  '$',  '%',  '&', '\'',
 
 957          '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
 
 958          '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
 
 959          '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
 
 960          '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',
 
 961          'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
 
 962          'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
 
 963          'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_',
 
 964          '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
 
 965          'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
 
 966          'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
 
 967          'x',  'y',  'z',  '{',  '|',  '}',  '~'
 
 970     code = code < sizeof table ? table[code] : -1;
 
 978 /*----------------------------------------------------------------.
 
 979 | Handle `#line INT "FILE"'.  ARGS has already skipped `#line '.  |
 
 980 `----------------------------------------------------------------*/
 
 983 handle_syncline (char *args)
 
 985   int lineno = strtol (args, &args, 10);
 
 986   const char *file = NULL;
 
 987   file = strchr (args, '"') + 1;
 
 988   *strchr (file, '"') = 0;
 
 989   scanner_cursor.file = current_file = xstrdup (file);
 
 990   scanner_cursor.line = lineno;
 
 991   scanner_cursor.column = 1;
 
 995 /*------------------------------------------------------------------------.
 
 996 | Report an unexpected EOF in a token or comment starting at START.       |
 
 997 | An end of file was encountered and the expected TOKEN_END was missing.  |
 
 998 `------------------------------------------------------------------------*/
 
1001 unexpected_eof (boundary start, char const *token_end)
 
1005   loc.end = scanner_cursor;
 
1006   complain_at (loc, _("missing `%s' at end of file"), token_end);
 
1010 /*-------------------------.
 
1011 | Initialize the scanner.  |
 
1012 `-------------------------*/
 
1015 scanner_initialize (void)
 
1017   obstack_init (&obstack_for_string);
 
1021 /*-----------------------------------------------.
 
1022 | Free all the memory allocated to the scanner.  |
 
1023 `-----------------------------------------------*/
 
1028   obstack_free (&obstack_for_string, 0);
 
1029   /* Reclaim Flex's buffers.  */
 
1030   yy_delete_buffer (YY_CURRENT_BUFFER);