]> git.saurik.com Git - bison.git/blobdiff - src/scan-gram.l
%define: accept unquoted values.
[bison.git] / src / scan-gram.l
index 9a733bc178fbcf6942e9057d367d6bf5073c8606..bcb7209b5101aa5d4d16b36200f71d61f7e64343 100644 (file)
@@ -1,7 +1,7 @@
 /* Bison Grammar Scanner                             -*- C -*-
 
 /* Bison Grammar Scanner                             -*- C -*-
 
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation,
-   Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
 
    This file is part of Bison, the GNU Compiler Compiler.
 
@@ -18,7 +18,7 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-%option debug nodefault nounput noyywrap never-interactive
+%option debug nodefault noinput nounput noyywrap never-interactive
 %option prefix="gram_" outfile="lex.yy.c"
 
 %{
 %option prefix="gram_" outfile="lex.yy.c"
 
 %{
@@ -37,6 +37,7 @@
 #include <src/reader.h>
 #include <src/uniqstr.h>
 
 #include <src/reader.h>
 #include <src/uniqstr.h>
 
+#include <ctype.h>
 #include <mbswidth.h>
 #include <quote.h>
 
 #include <mbswidth.h>
 #include <quote.h>
 
@@ -55,9 +56,27 @@ static boundary scanner_cursor;
 static size_t no_cr_read (FILE *, char *, size_t);
 #define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
 
 static size_t no_cr_read (FILE *, char *, size_t);
 #define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
 
+#define RETURN_PERCENT_FLAG(Value)              \
+  do {                                          \
+    val->uniqstr = uniqstr_new (Value);         \
+    return PERCENT_FLAG;                        \
+  } while (0)
+
+#define ROLLBACK_CURRENT_TOKEN                                  \
+  do {                                                          \
+    scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);    \
+    yyless (0);                                                 \
+  } while (0)
+
 /* A string representing the most recently saved token.  */
 static char *last_string;
 
 /* A string representing the most recently saved token.  */
 static char *last_string;
 
+/* Bracketed identifier. */
+static uniqstr bracketed_id_str = 0;
+static location bracketed_id_loc;
+static boundary bracketed_id_start;
+static int bracketed_id_context_state = 0;
+
 void
 gram_scanner_last_string_free (void)
 {
 void
 gram_scanner_last_string_free (void)
 {
@@ -90,10 +109,12 @@ static void unexpected_newline (boundary, char const *);
 %x SC_COMMENT SC_LINE_COMMENT
  /* Strings and characters in code. */
 %x SC_STRING SC_CHARACTER
 %x SC_COMMENT SC_LINE_COMMENT
  /* Strings and characters in code. */
 %x SC_STRING SC_CHARACTER
+ /* Bracketed identifiers support. */
+%x SC_BRACKETED_ID SC_RETURN_BRACKETED_ID
 
 
-letter   [.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
+letter   [-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]
 id       {letter}({letter}|[0-9])*
 id       {letter}({letter}|[0-9])*
-directive %{letter}({letter}|[0-9]|-)*
+directive %{id}
 int      [0-9]+
 
 /* POSIX says that a tag must be both an id and a C union member, but
 int      [0-9]+
 
 /* POSIX says that a tag must be both an id and a C union member, but
@@ -134,7 +155,7 @@ splice       (\\[ \f\t\v]*\n)*
   | Scanning white space.  |
   `-----------------------*/
 
   | Scanning white space.  |
   `-----------------------*/
 
-<INITIAL,SC_AFTER_IDENTIFIER>
+<INITIAL,SC_AFTER_IDENTIFIER,SC_BRACKETED_ID,SC_RETURN_BRACKETED_ID>
 {
   /* Comments and white space.  */
   ","         warn_at (*loc, _("stray `,' treated as white space"));
 {
   /* Comments and white space.  */
   ","         warn_at (*loc, _("stray `,' treated as white space"));
@@ -168,7 +189,7 @@ splice       (\\[ \f\t\v]*\n)*
 {
   "%binary"                         return PERCENT_NONASSOC;
   "%code"                           return PERCENT_CODE;
 {
   "%binary"                         return PERCENT_NONASSOC;
   "%code"                           return PERCENT_CODE;
-  "%debug"                          return PERCENT_DEBUG;
+  "%debug"                          RETURN_PERCENT_FLAG("parse.trace");
   "%default"[-_]"prec"              return PERCENT_DEFAULT_PREC;
   "%define"                         return PERCENT_DEFINE;
   "%defines"                        return PERCENT_DEFINES;
   "%default"[-_]"prec"              return PERCENT_DEFAULT_PREC;
   "%define"                         return PERCENT_DEFINE;
   "%defines"                        return PERCENT_DEFINES;
@@ -184,7 +205,7 @@ splice       (\\[ \f\t\v]*\n)*
   "%language"                       return PERCENT_LANGUAGE;
   "%left"                           return PERCENT_LEFT;
   "%lex-param"                      return PERCENT_LEX_PARAM;
   "%language"                       return PERCENT_LANGUAGE;
   "%left"                           return PERCENT_LEFT;
   "%lex-param"                      return PERCENT_LEX_PARAM;
-  "%locations"                      return PERCENT_LOCATIONS;
+  "%locations"                      RETURN_PERCENT_FLAG("locations");
   "%merge"                          return PERCENT_MERGE;
   "%name"[-_]"prefix"               return PERCENT_NAME_PREFIX;
   "%no"[-_]"default"[-_]"prec"      return PERCENT_NO_DEFAULT_PREC;
   "%merge"                          return PERCENT_MERGE;
   "%name"[-_]"prefix"               return PERCENT_NAME_PREFIX;
   "%no"[-_]"default"[-_]"prec"      return PERCENT_NO_DEFAULT_PREC;
@@ -197,7 +218,7 @@ splice       (\\[ \f\t\v]*\n)*
   "%prec"                           return PERCENT_PREC;
   "%precedence"                     return PERCENT_PRECEDENCE;
   "%printer"                        return PERCENT_PRINTER;
   "%prec"                           return PERCENT_PREC;
   "%precedence"                     return PERCENT_PRECEDENCE;
   "%printer"                        return PERCENT_PRINTER;
-  "%pure"[-_]"parser"               return PERCENT_PURE_PARSER;
+  "%pure"[-_]"parser"               RETURN_PERCENT_FLAG("api.pure");
   "%require"                        return PERCENT_REQUIRE;
   "%right"                          return PERCENT_RIGHT;
   "%skeleton"                       return PERCENT_SKELETON;
   "%require"                        return PERCENT_REQUIRE;
   "%right"                          return PERCENT_RIGHT;
   "%skeleton"                       return PERCENT_SKELETON;
@@ -221,6 +242,7 @@ splice       (\\[ \f\t\v]*\n)*
   {id} {
     val->uniqstr = uniqstr_new (yytext);
     id_loc = *loc;
   {id} {
     val->uniqstr = uniqstr_new (yytext);
     id_loc = *loc;
+    bracketed_id_str = NULL;
     BEGIN SC_AFTER_IDENTIFIER;
   }
 
     BEGIN SC_AFTER_IDENTIFIER;
   }
 
@@ -233,8 +255,14 @@ splice      (\\[ \f\t\v]*\n)*
     return INT;
   }
 
     return INT;
   }
 
-  /* Characters.  We don't check there is only one.  */
-  "'"        STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
+  /* Identifiers may not start with a digit.  Yet, don't silently
+     accept "1FOO" as "1 FOO".  */
+  {int}{id} {
+    complain_at (*loc, _("invalid identifier: %s"), quote (yytext));
+  }
+
+  /* Characters.  */
+  "'"        token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
 
   /* Strings. */
   "\""       token_start = loc->start; BEGIN SC_ESCAPED_STRING;
 
   /* Strings. */
   "\""       token_start = loc->start; BEGIN SC_ESCAPED_STRING;
@@ -273,6 +301,13 @@ splice      (\\[ \f\t\v]*\n)*
     return PERCENT_PERCENT;
   }
 
     return PERCENT_PERCENT;
   }
 
+  "[" {
+    bracketed_id_str = NULL;
+    bracketed_id_start = loc->start;
+    bracketed_id_context_state = YY_START;
+    BEGIN SC_BRACKETED_ID;
+  }
+
   . {
     complain_at (*loc, _("invalid character: %s"), quote (yytext));
   }
   . {
     complain_at (*loc, _("invalid character: %s"), quote (yytext));
   }
@@ -301,25 +336,94 @@ splice     (\\[ \f\t\v]*\n)*
 
 <SC_AFTER_IDENTIFIER>
 {
 
 <SC_AFTER_IDENTIFIER>
 {
+  "[" {
+    if (bracketed_id_str)
+      {
+       ROLLBACK_CURRENT_TOKEN;
+       BEGIN SC_RETURN_BRACKETED_ID;
+       *loc = id_loc;
+       return ID;
+      }
+    else
+      {
+       bracketed_id_start = loc->start;
+       bracketed_id_context_state = YY_START;
+       BEGIN SC_BRACKETED_ID;
+      }
+  }
   ":" {
   ":" {
+    BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
     *loc = id_loc;
     *loc = id_loc;
-    BEGIN INITIAL;
     return ID_COLON;
   }
   . {
     return ID_COLON;
   }
   . {
-    scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);
-    yyless (0);
+    ROLLBACK_CURRENT_TOKEN;
+    BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
     *loc = id_loc;
     *loc = id_loc;
-    BEGIN INITIAL;
     return ID;
   }
   <<EOF>> {
     return ID;
   }
   <<EOF>> {
+    BEGIN (bracketed_id_str ? SC_RETURN_BRACKETED_ID : INITIAL);
     *loc = id_loc;
     *loc = id_loc;
-    BEGIN INITIAL;
     return ID;
   }
 }
 
     return ID;
   }
 }
 
+  /*--------------------------------.
+  | Scanning bracketed identifiers. |
+  `--------------------------------*/
+
+<SC_BRACKETED_ID>
+{
+  {id} {
+    if (bracketed_id_str)
+      {
+       complain_at (*loc, _("unexpected identifier in bracketed name: %s"),
+                    quote (yytext));
+      }
+    else
+      {
+       bracketed_id_str = uniqstr_new (yytext);
+       bracketed_id_loc = *loc;
+      }
+  }
+  "]" {
+    BEGIN bracketed_id_context_state;
+    if (bracketed_id_str)
+      {
+       if (INITIAL == bracketed_id_context_state)
+         {
+           val->uniqstr = bracketed_id_str;
+           bracketed_id_str = 0;
+           *loc = bracketed_id_loc;
+           return BRACKETED_ID;
+         }
+      }
+    else
+      complain_at (*loc, _("an identifier expected"));
+  }
+  . {
+    complain_at (*loc, _("invalid character in bracketed name: %s"),
+                quote (yytext));
+  }
+  <<EOF>> {
+    BEGIN bracketed_id_context_state;
+    unexpected_eof (bracketed_id_start, "]");
+  }
+}
+
+<SC_RETURN_BRACKETED_ID>
+{
+  . {
+    ROLLBACK_CURRENT_TOKEN;
+    val->uniqstr = bracketed_id_str;
+    bracketed_id_str = 0;
+    *loc = bracketed_id_loc;
+    BEGIN INITIAL;
+    return BRACKETED_ID;
+  }
+}
+
 
   /*---------------------------------------------------------------.
   | Scanning a Yacc comment.  The initial `/ *' is already eaten.  |
 
   /*---------------------------------------------------------------.
   | Scanning a Yacc comment.  The initial `/ *' is already eaten.  |
@@ -390,24 +494,42 @@ splice     (\\[ \f\t\v]*\n)*
 <SC_ESCAPED_CHARACTER>
 {
   "'"|"\n" {
 <SC_ESCAPED_CHARACTER>
 {
   "'"|"\n" {
-    if (yytext[0] == '\n')
-      unexpected_newline (token_start, "'");
-    STRING_GROW;
     STRING_FINISH;
     loc->start = token_start;
     STRING_FINISH;
     loc->start = token_start;
-    val->character = last_string[1];
+    val->character = last_string[0];
+    {
+      /* FIXME: Eventually, make these errors.  */
+      if (last_string[0] == '\0')
+        {
+          warn_at (*loc, _("empty character literal"));
+          /* '\0' seems dangerous even if we are about to complain.  */
+          val->character = '\'';
+        }
+      else if (last_string[1] != '\0')
+        warn_at (*loc, _("extra characters in character literal"));
+    }
+    if (yytext[0] == '\n')
+      unexpected_newline (token_start, "'");
     STRING_FREE;
     BEGIN INITIAL;
     return CHAR;
   }
   <<EOF>> {
     STRING_FREE;
     BEGIN INITIAL;
     return CHAR;
   }
   <<EOF>> {
-    unexpected_eof (token_start, "'");
     STRING_FINISH;
     loc->start = token_start;
     STRING_FINISH;
     loc->start = token_start;
-    if (strlen(last_string) > 1)
-      val->character = last_string[1];
-    else
-      val->character = last_string[0];
+    val->character = last_string[0];
+    {
+      /* FIXME: Eventually, make these errors.  */
+      if (last_string[0] == '\0')
+        {
+          warn_at (*loc, _("empty character literal"));
+          /* '\0' seems dangerous even if we are about to complain.  */
+          val->character = '\'';
+        }
+      else if (last_string[1] != '\0')
+        warn_at (*loc, _("extra characters in character literal"));
+    }
+    unexpected_eof (token_start, "'");
     STRING_FREE;
     BEGIN INITIAL;
     return CHAR;
     STRING_FREE;
     BEGIN INITIAL;
     return CHAR;
@@ -457,10 +579,9 @@ splice      (\\[ \f\t\v]*\n)*
 {
   \\[0-7]{1,3} {
     unsigned long int c = strtoul (yytext + 1, NULL, 8);
 {
   \\[0-7]{1,3} {
     unsigned long int c = strtoul (yytext + 1, NULL, 8);
-    if (UCHAR_MAX < c)
-      complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
-    else if (! c)
-      complain_at (*loc, _("invalid null character: %s"), quote (yytext));
+    if (!c || UCHAR_MAX < c)
+      complain_at (*loc, _("invalid number after \\-escape: %s"),
+                   yytext+1);
     else
       obstack_1grow (&obstack_for_string, c);
   }
     else
       obstack_1grow (&obstack_for_string, c);
   }
@@ -468,10 +589,9 @@ splice      (\\[ \f\t\v]*\n)*
   \\x[0-9abcdefABCDEF]+ {
     verify (UCHAR_MAX < ULONG_MAX);
     unsigned long int c = strtoul (yytext + 2, NULL, 16);
   \\x[0-9abcdefABCDEF]+ {
     verify (UCHAR_MAX < ULONG_MAX);
     unsigned long int c = strtoul (yytext + 2, NULL, 16);
-    if (UCHAR_MAX < c)
-      complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
-    else if (! c)
-      complain_at (*loc, _("invalid null character: %s"), quote (yytext));
+    if (!c || UCHAR_MAX < c)
+      complain_at (*loc, _("invalid number after \\-escape: %s"),
+                   yytext+1);
     else
       obstack_1grow (&obstack_for_string, c);
   }
     else
       obstack_1grow (&obstack_for_string, c);
   }
@@ -489,16 +609,20 @@ splice     (\\[ \f\t\v]*\n)*
 
   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
     int c = convert_ucn_to_byte (yytext);
 
   \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
     int c = convert_ucn_to_byte (yytext);
-    if (c < 0)
-      complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
-    else if (! c)
-      complain_at (*loc, _("invalid null character: %s"), quote (yytext));
+    if (c <= 0)
+      complain_at (*loc, _("invalid number after \\-escape: %s"),
+                   yytext+1);
     else
       obstack_1grow (&obstack_for_string, c);
   }
   \\(.|\n)     {
     else
       obstack_1grow (&obstack_for_string, c);
   }
   \\(.|\n)     {
-    complain_at (*loc, _("unrecognized escape sequence: %s"), quote (yytext));
-    STRING_GROW;
+    char const *p = yytext + 1;
+    /* Quote only if escaping won't make the character visible.  */
+    if (isspace ((unsigned char) *p) && isprint ((unsigned char) *p))
+      p = quote (p);
+    else
+      p = quotearg_style_mem (escape_quoting_style, p, 1);
+    complain_at (*loc, _("invalid character after \\-escape: %s"), p);
   }
 }
 
   }
 }