bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Bison patch to allow rules without trailing semicolon


From: Paul Eggert
Subject: Bison patch to allow rules without trailing semicolon
Date: Fri, 6 Dec 2002 22:19:36 -0800 (PST)

I installed the following patch.

2002-12-06  Paul Eggert  <address@hidden>

        Add support for rules that do not have trailing semicolons, as
        POSIX requires.  Improve the quality of locations in Bison
        diagnostics.
        
        * src/location.c: Include <quotearg.h>.
        (empty_location): Now const.
        (location_print): New function.  Follow the recommendation of the
        GNU Coding Standards for locations that span file boundaries.
        * src/location.h: Do not include <quotearg.h>; no longer needed.
        (boundary): New type.
        (location_t): Use it.  This allows locations to span file boundaries.
        All member uses changed: file -> start.file or end.file (as needed),
        first_line -> start.line, first_column -> start.column,
        last_line -> end.line, last_column -> end.column.
        (equal_boundaries): New function.
        (LOCATION_RESET, LOCATION_STEP): Remove.
        (LOCATION_PRINT): Remove.  All callers changed to use location_print.
        (empty_location): Now const.
        (location_print): New decl.
        * src/parse-gram.y (lloc_default): New function, which handles
        empty locations more accurately.
        (YYLLOC_DEFAULT): Use it.
        (%token COLON): Remove.
        (%token ID_COLON): New token.
        (rules): Use it.        
        (declarations, rules): Remove trailing semicolon.
        (declaration, rules_or_grammar_declaration):
        Allow empty (";") declaration.
        (symbol_def): Remove empty actions; no longer needed.
        (rules_or_grammar_declaration): Remove trailing semicolon.
        (semi_colon.opt): Remove.
        * src/reader.h: Include location.h.
        (scanner_cursor): New decl.
        * src/reduce.c (nonterminals_reduce): Use warn_at rather than
        rolling our own.
        * src/scan-gram.l (YY_USER_INIT): Initialize scanner_cursor instead
        of *loc.
        (STEP): Remove.  No longer needed, now that adjust_location does
        the work.  All uses removed.
        (scanner_cursor): New var.
        (adjust_location): Renamed from extend_location.  It now sets
        *loc and adjusts the scanner cursor.  All uses changed.
        Don't bother testing for CR.
        (handle_syncline): Remove location arg; now updates scanner cursor.
        All callers changed.
        (unexpected_end_of_file): Now accepts start boundary of token or
        comment, not location.  All callers changed.  Update scanner cursor,
        not the location.
        (SC_AFTER_IDENTIFIER): New state.
        (context_state): Renamed from c_context.  All uses changed.
        (id_loc, code_start, token_start): New local vars.
        (<INITIAL,SC_AFTER_IDENTIFIER>): New initial context.  Move all
        processing of Yacc white space and equivalents here.
        (<INITIAL>{id}): Save id_loc.  Begin state SC_AFTER_IDENTIFIER
        instead of returning ID immediately, since we need to search for
        a subsequent colon.
        (<INITIAL>"'", "\""): Save token_start.
        (<INITIAL>"%{", "{", "%%"): Save code_start.
        (<SC_AFTER_IDENTIFIER>): New state, looking for a colon.
        (<SC_YACC_COMMENT>, <SC_COMMENT>, <SC_LINE_COMMENT>):
        BEGIN context_state at end, not INITIAL.
        (<SC_ESCAPED_STRING>"\"", <SC_ESCAPED_CHARACTER>"'",
        <SC_BRACED_CODE>"}", <SC_PROLOGUE>"%}", <SC_EPILOGUE><<EOF>>):
        Return correct token start.
        (<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>): Save start boundary when
        the start of a character, string or multiline comment is found.
        * tests/conflicts.at (S/R in initial, Defaulted Conflicted
        Reduction): Adjust reported locations to match the more-precise
        results now expected.
        * tests/input.at (Invalid $n, Invalid @n, Type Clashes): Likewise.
        * tests/reduce.at (Useless Rules, Reduced Automaton,
        Underivable Rules): Likewise.
        * tests/regression.at (Invalid inputs): No longer `expecting ";"
        or "|"' now that so many other tokens are allowed by the new grammar.

        * src/complain.h (current_file): Remove duplicate decl;
        current_file is now owned by files.h.
        * src/complain.c, src/scan-gram.l: Include files.h.

Index: src/complain.c
===================================================================
RCS file: /cvsroot/bison/bison/src/complain.c,v
retrieving revision 1.17
diff -p -u -r1.17 complain.c
--- src/complain.c      12 Nov 2002 08:05:59 -0000      1.17
+++ src/complain.c      7 Dec 2002 05:41:57 -0000
@@ -1,5 +1,5 @@
 /* Declaration for error-reporting function for Bison.
-   Copyright (C) 2000, 2001, 2002  Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -32,6 +32,7 @@
 #endif
 
 #include "complain.h"
+#include "files.h"
 
 #ifndef _
 # define _(String) String
@@ -98,7 +99,7 @@ warn_at (location_t location, const char
   va_list args;
 
   fflush (stdout);
-  LOCATION_PRINT (stderr, location);
+  location_print (stderr, location);
   fputs (": ", stderr);
   fputs (_("warning: "), stderr);
 
@@ -138,7 +139,7 @@ complain_at (location_t location, const 
   va_list args;
 
   fflush (stdout);
-  LOCATION_PRINT (stderr, location);
+  location_print (stderr, location);
   fputs (": ", stderr);
 
   va_start (args, message);
@@ -177,7 +178,7 @@ fatal_at (location_t location, const cha
   va_list args;
 
   fflush (stdout);
-  LOCATION_PRINT (stderr, location);
+  location_print (stderr, location);
   fputs (": ", stderr);
   fputs (_("fatal error: "), stderr);
 
Index: src/complain.h
===================================================================
RCS file: /cvsroot/bison/bison/src/complain.h,v
retrieving revision 1.12
diff -p -u -r1.12 complain.h
--- src/complain.h      12 Nov 2002 08:05:59 -0000      1.12
+++ src/complain.h      7 Dec 2002 05:41:57 -0000
@@ -49,9 +49,6 @@ void fatal (const char *format, ...)
 void fatal_at (location_t location, const char *format, ...)
   __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
 
-/* Position in the current input file. */
-extern const char *current_file;
-
 /* This variable is set each time `warn' is called.  */
 extern bool warning_issued;
 
Index: src/gram.c
===================================================================
RCS file: /cvsroot/bison/bison/src/gram.c,v
retrieving revision 1.46
diff -p -u -r1.46 gram.c
--- src/gram.c  22 Oct 2002 04:41:25 -0000      1.46
+++ src/gram.c  7 Dec 2002 05:41:57 -0000
@@ -316,7 +316,7 @@ grammar_rules_never_reduced_report (cons
   for (r = 0; r < nrules ; ++r)
     if (!rules[r].useful)
       {
-       LOCATION_PRINT (stderr, rules[r].location);
+       location_print (stderr, rules[r].location);
        fprintf (stderr, ": %s: %s: ",
                 _("warning"), message);
        rule_print (&rules[r], stderr);
Index: src/location.c
===================================================================
RCS file: /cvsroot/bison/bison/src/location.c,v
retrieving revision 1.2
diff -p -u -r1.2 location.c
--- src/location.c      9 Jul 2002 16:24:57 -0000       1.2
+++ src/location.c      7 Dec 2002 05:41:57 -0000
@@ -1,5 +1,5 @@
 /* Locations for Bison
-   Copyright (C) 2002  Free Software Foundation, Inc.
+   Copyright (C) 2002 Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
@@ -20,5 +20,25 @@
 
 #include "system.h"
 #include "location.h"
+#include <quotearg.h>
 
-location_t empty_location = { NULL, 0, 0, 0, 0 };
+location_t const empty_location;
+
+/* Output to OUT the location LOC.
+   Warning: it uses quotearg's slot 3.  */
+void
+location_print (FILE *out, location_t loc)
+{
+  fprintf (out, "%s:%d.%d",
+          quotearg_n_style (3, escape_quoting_style, loc.start.file),
+          loc.start.line, loc.start.column);
+
+  if (loc.start.file != loc.end.file)
+    fprintf (out, "-%s:%d.%d",
+            quotearg_n_style (3, escape_quoting_style, loc.end.file),
+            loc.end.line, loc.end.column - 1);
+  else if (loc.start.line < loc.end.line)
+    fprintf (out, "-%d.%d", loc.end.line, loc.end.column - 1);
+  else if (loc.start.column < loc.end.column - 1)
+    fprintf (out, "-%d", loc.end.column - 1);
+}
Index: src/location.h
===================================================================
RCS file: /cvsroot/bison/bison/src/location.h,v
retrieving revision 1.6
diff -p -u -r1.6 location.h
--- src/location.h      12 Nov 2002 08:30:47 -0000      1.6
+++ src/location.h      7 Dec 2002 05:41:57 -0000
@@ -1,5 +1,5 @@
 /* Locations for Bison
-   Copyright (C) 2002  Free Software Foundation, Inc.
+   Copyright (C) 2002 Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
@@ -20,56 +20,46 @@
 
 #ifndef LOCATION_H_
 # define LOCATION_H_
-# include "quotearg.h"
 
-typedef struct location_s
+/* A boundary between two characters.  */
+typedef struct
 {
-  const char *file;
-  int first_line;
-  int first_column;
-  int last_line;
-  int last_column;
-}  location_t;
-#define YYLTYPE location_t
+  /* The name of the file that contains the boundary.  */
+  char const *file;
+
+  /* The (origin-1) line that contains the boundary.  */
+  int line;
+
+  /* The (origin-1) column just after the boundary.  This is neither a
+     byte count, nor a character count; it is a column count.  */
+  int column;
+
+} boundary;
+
+/* Return nonzero if A and B are equal boundaries.  */
+static inline bool
+equal_boundaries (boundary a, boundary b)
+{
+  return (a.column == b.column
+         && a.line == b.line
+         && a.file == b.file);
+}
 
-/* Initialize LOC. */
-# define LOCATION_RESET(Loc)                   \
-do {                                           \
-  (Loc).file = NULL;                           \
-  (Loc).first_column = (Loc).first_line = 1;   \
-  (Loc).last_column =  (Loc).last_line = 1;    \
-} while (0)
-
-
-/* Restart: move the first cursor to the last position. */
-# define LOCATION_STEP(Loc)                    \
-do {                                           \
-  (Loc).first_column = (Loc).last_column;      \
-  (Loc).first_line = (Loc).last_line;          \
-} while (0)
-
-
-/* Output LOC on the stream OUT.
-   Warning: it uses quotearg's slot 3.  */
-# define LOCATION_PRINT(Out, Loc)                                      \
-do {                                                                   \
-  fprintf (stderr, "%s:", quotearg_n_style (3, escape_quoting_style,   \
-                                           (Loc).file));               \
-  if ((Loc).first_line)                                                        
\
-    {                                                                  \
-      if ((Loc).first_line != (Loc).last_line)                         \
-       fprintf (Out, "%d.%d-%d.%d",                                    \
-                (Loc).first_line, (Loc).first_column,                  \
-                (Loc).last_line, (Loc).last_column - 1);               \
-      else if ((Loc).first_column < (Loc).last_column - 1)             \
-       fprintf (Out, "%d.%d-%d", (Loc).first_line,                     \
-                (Loc).first_column, (Loc).last_column - 1);            \
-      else                                                             \
-       fprintf (Out, "%d.%d", (Loc).first_line, (Loc).first_column);   \
-  }                                                                    \
-} while (0)
+/* A location, that is, a region of source code.  */
+typedef struct
+{
+  /* Boundary just before the location starts.  */
+  boundary start;
+
+  /* Boundary just after the location ends.  */
+  boundary end;
+
+} location_t;
+
+#define YYLTYPE location_t
 
+extern location_t const empty_location;
 
-extern location_t empty_location;
+void location_print (FILE *, location_t);
 
-#endif /* !LOCATION_H_ */
+#endif /* ! defined LOCATION_H_ */
Index: src/output.c
===================================================================
RCS file: /cvsroot/bison/bison/src/output.c,v
retrieving revision 1.212
diff -p -u -r1.212 output.c
--- src/output.c        21 Nov 2002 05:20:05 -0000      1.212
+++ src/output.c        7 Dec 2002 05:41:58 -0000
@@ -229,7 +229,7 @@ prepare_rules (void)
       /* Separator in RHS. */
       rhs[i++] = -1;
       /* Line where rule was defined. */
-      rline[r] = rules[r].location.first_line;
+      rline[r] = rules[r].location.start.line;
       /* Dynamic precedence (GLR).  */
       dprec[r] = rules[r].dprec;
       /* Merger-function index (GLR).  */
@@ -295,8 +295,8 @@ user_actions_output (FILE *out)
        fprintf (out, "  case %d:\n", r + 1);
 
        fprintf (out, "]b4_syncline([[%d]], ",
-                rules[r].action_location.first_line);
-       escaped_file_name_output (out, rules[r].action_location.file);
+                rules[r].action_location.start.line);
+       escaped_file_name_output (out, rules[r].action_location.start.file);
        fprintf (out, ")[\n");
        fprintf (out, "    %s\n    break;\n\n",
                 rules[r].action);
@@ -399,9 +399,9 @@ symbol_destructors_output (FILE *out)
           destructor, typename. */
        fprintf (out, "%s[",
                 first ? "" : ",\n");
-       escaped_file_name_output (out, symbol->destructor_location.file);
+       escaped_file_name_output (out, symbol->destructor_location.start.file);
        fprintf (out, ", [[%d]], [[%s]], [[%d]], [[%s]], [[%s]]]",
-                symbol->destructor_location.first_line,
+                symbol->destructor_location.start.line,
                 symbol->tag,
                 symbol->number,
                 symbol->destructor,
@@ -434,9 +434,9 @@ symbol_printers_output (FILE *out)
           printer, typename. */
        fprintf (out, "%s[",
                 first ? "" : ",\n");
-       escaped_file_name_output (out, symbol->printer_location.file);
+       escaped_file_name_output (out, symbol->printer_location.start.file);
        fprintf (out, ", [[%d]], [[%s]], [[%d]], [[%s]], [[%s]]]",
-                symbol->printer_location.first_line,
+                symbol->printer_location.start.line,
                 symbol->tag,
                 symbol->number,
                 symbol->printer,
Index: src/parse-gram.y
===================================================================
RCS file: /cvsroot/bison/bison/src/parse-gram.y,v
retrieving revision 1.33
diff -p -u -r1.33 parse-gram.y
--- src/parse-gram.y    30 Nov 2002 09:16:54 -0000      1.33
+++ src/parse-gram.y    7 Dec 2002 05:41:58 -0000
@@ -42,20 +42,9 @@
 
 /* Produce verbose syntax errors.  */
 #define YYERROR_VERBOSE 1
-#define YYLLOC_DEFAULT(Current, Rhs, N)                        \
-do {                                                   \
-  if (N)                                               \
-  {                                                    \
-    Current.first_column  = Rhs[1].first_column;       \
-    Current.first_line    = Rhs[1].first_line;         \
-    Current.last_column   = Rhs[N].last_column;                \
-    Current.last_line     = Rhs[N].last_line;          \
-  }                                                    \
-  else                                                 \
-  {                                                    \
-    Current = Rhs[0];                                  \
-  }                                                    \
-} while (0)
+
+#define YYLLOC_DEFAULT(Current, Rhs, N)  (Current) = lloc_default (Rhs, N)
+static YYLTYPE lloc_default (YYLTYPE const *, int);
 
 /* Request detailed syntax error messages, and pass them to GRAM_ERROR.
    FIXME: depends on the undocumented availability of YYLLOC.  */
@@ -143,9 +132,9 @@ braced_code_t current_braced_code = acti
 %token TYPE            "type"
 %token EQUAL           "="
 %token SEMICOLON       ";"
-%token COLON           ":"
 %token PIPE            "|"
 %token ID              "identifier"
+%token ID_COLON        "identifier:"
 %token PERCENT_PERCENT "%%"
 %token PROLOGUE        "%{...%}"
 %token EPILOGUE        "epilogue"
@@ -157,7 +146,7 @@ braced_code_t current_braced_code = acti
                PROLOGUE EPILOGUE
 %type <struniq> TYPE
 %type <integer> INT
-%type <symbol> ID symbol string_as_id
+%type <symbol> ID ID_COLON symbol string_as_id
 %type <assoc> precedence_declarator
 %type <list>  symbols.1
 %%
@@ -173,7 +162,7 @@ input:
 
 declarations:
   /* Nothing */
-| declarations declaration semi_colon.opt
+| declarations declaration
 ;
 
 declaration:
@@ -197,6 +186,7 @@ declaration:
 | "%token-table"                           { token_table_flag = 1; }
 | "%verbose"                               { report_flag = 1; }
 | "%yacc"                                  { yacc_flag = 1; }
+| ";"
 ;
 
 grammar_declaration:
@@ -209,7 +199,7 @@ grammar_declaration:
 | "%union" BRACED_CODE
     {
       typed = 1;
-      MUSCLE_INSERT_INT ("stype_line", @2.first_line);
+      MUSCLE_INSERT_INT ("stype_line", @2.start.line);
       muscle_insert ("stype", $2);
     }
 | "%destructor"
@@ -322,9 +312,7 @@ symbol_def:
 /* One or more symbol definitions. */
 symbol_defs.1:
   symbol_def
-    {;}
 | symbol_defs.1 symbol_def
-    {;}
 ;
 
 
@@ -338,11 +326,10 @@ grammar:
 ;
 
 /* As a Bison extension, one can use the grammar declarations in the
-   body of the grammar.  But to remain LALR(1), they must be ended
-   with a semi-colon.  */
+   body of the grammar.  */
 rules_or_grammar_declaration:
   rules
-| grammar_declaration ";"
+| grammar_declaration
     {
       if (yacc_flag)
        complain_at (@$, _("POSIX forbids declarations in the grammar"));
@@ -351,11 +338,11 @@ rules_or_grammar_declaration:
     {
       yyerrok;
     }
+| ";"
 ;
 
 rules:
-  ID ":" { current_lhs = $1; current_lhs_location = @1; } rhses.1 ";"
-    {;}
+  ID_COLON { current_lhs = $1; current_lhs_location = @1; } rhses.1
 ;
 
 rhses.1:
@@ -424,11 +411,42 @@ epilogue.opt:
     }
 ;
 
-semi_colon.opt:
-  /* Nothing.  */
-| ";"
-;
 %%
+
+
+/* Return the location of the left-hand side of a rule whose
+   right-hand side is RHS[1] ... RHS[N].  Ignore empty nonterminals in
+   the right-hand side, and return an empty location equal to the end
+   boundary of RHS[0] if the right-hand side is empty.  */
+
+static YYLTYPE
+lloc_default (YYLTYPE const *rhs, int n)
+{
+  int i;
+  int j;
+  YYLTYPE r;
+  r.start = r.end = rhs[n].end;
+
+  for (i = 1; i <= n; i++)
+    if (! equal_boundaries (rhs[i].start, rhs[i].end))
+      {
+       r.start = rhs[i].start;
+
+       for (j = n; i < j; j--)
+         if (! equal_boundaries (rhs[j].start, rhs[j].end))
+           break;
+       r.end = rhs[j].end;
+
+       break;
+      }
+
+  return r;
+}
+
+
+/* Add a lex-param or a parse-param (depending on TYPE) with
+   declaration DECL and location LOC.  */
+
 static void
 add_param (char const *type, char const *decl, location_t loc)
 {
Index: src/reader.c
===================================================================
RCS file: /cvsroot/bison/bison/src/reader.c,v
retrieving revision 1.226
diff -p -u -r1.226 reader.c
--- src/reader.c        30 Nov 2002 09:52:11 -0000      1.226
+++ src/reader.c        7 Dec 2002 05:41:58 -0000
@@ -70,8 +70,9 @@ prologue_augment (const char *prologue, 
     !typed ? &pre_prologue_obstack : &post_prologue_obstack;
 
   obstack_fgrow1 (oout, "]b4_syncline([[%d]], [[",
-                 location.first_line);
-  MUSCLE_OBSTACK_SGROW (oout, quotearg_style (c_quoting_style, location.file));
+                 location.start.line);
+  MUSCLE_OBSTACK_SGROW (oout, quotearg_style (c_quoting_style,
+                                             location.start.file));
   obstack_sgrow (oout, "]])[\n");
   obstack_sgrow (oout, prologue);
 }
@@ -88,9 +89,9 @@ epilogue_augment (const char *epilogue, 
 {
   char *extension = NULL;
   obstack_fgrow1 (&muscle_obstack, "]b4_syncline([[%d]], [[",
-                 location.first_line);
+                 location.start.line);
   MUSCLE_OBSTACK_SGROW (&muscle_obstack,
-                       quotearg_style (c_quoting_style, location.file));
+                       quotearg_style (c_quoting_style, location.start.file));
   obstack_sgrow (&muscle_obstack, "]])[\n");
   obstack_sgrow (&muscle_obstack, epilogue);
   obstack_1grow (&muscle_obstack, 0);
Index: src/reader.h
===================================================================
RCS file: /cvsroot/bison/bison/src/reader.h,v
retrieving revision 1.33
retrieving revision 1.34
diff -p -u -r1.33 -r1.34
--- src/reader.h        30 Nov 2002 09:16:32 -0000      1.33
+++ src/reader.h        7 Dec 2002 06:11:11 -0000       1.34
@@ -1,5 +1,5 @@
 /* Input parser for bison
-   Copyright (C) 2000, 2001, 2002  Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
@@ -21,6 +21,7 @@
 #ifndef READER_H_
 # define READER_H_
 
+# include "location.h"
 # include "symlist.h"
 # include "parse-gram.h"
 
@@ -35,6 +36,7 @@ merger_list;
 /* From the scanner.  */
 extern FILE *gram_in;
 extern int gram__flex_debug;
+extern boundary scanner_cursor;
 void scanner_initialize (void);
 void scanner_free (void);
 void scanner_last_string_free (void);
Index: src/reduce.c
===================================================================
RCS file: /cvsroot/bison/bison/src/reduce.c,v
retrieving revision 1.77
diff -p -u -r1.77 reduce.c
--- src/reduce.c        12 Nov 2002 08:05:59 -0000      1.77
+++ src/reduce.c        7 Dec 2002 05:41:59 -0000
@@ -1,5 +1,5 @@
 /* Grammar reduction for Bison.
-   Copyright (C) 1988, 1989, 2000, 2001, 2002  Free Software Foundation, Inc.
+   Copyright (C) 1988, 1989, 2000, 2001, 2002 Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
@@ -297,9 +297,7 @@ nonterminals_reduce (void)
     if (!bitset_test (V, i))
       {
        nontermmap[i] = n++;
-       LOCATION_PRINT (stderr, symbols[i]->location);
-       fprintf (stderr, ": %s: %s: %s\n",
-                _("warning"), _("useless nonterminal"),
+       warn_at (symbols[i]->location, _("useless nonterminal: %s"),
                 symbols[i]->tag);
       }
 
Index: src/scan-gram.l
===================================================================
RCS file: /cvsroot/bison/bison/src/scan-gram.l,v
retrieving revision 1.47
diff -p -u -r1.47 scan-gram.l
--- src/scan-gram.l     1 Dec 2002 02:37:56 -0000       1.47
+++ src/scan-gram.l     7 Dec 2002 05:41:59 -0000
@@ -26,23 +26,27 @@
 #include "system.h"
 #include "mbswidth.h"
 #include "complain.h"
+#include "files.h"
 #include "quote.h"
 #include "struniq.h"
 #include "getargs.h"
 #include "gram.h"
 #include "reader.h"
 
-#define YY_USER_INIT                           \
-do {                                           \
-  LOCATION_RESET (*loc);                       \
-  loc->file = current_file;                    \
-} while (0)
+#define YY_USER_INIT                                   \
+  do                                                   \
+    {                                                  \
+      scanner_cursor.file = current_file;              \
+      scanner_cursor.line = 1;                         \
+      scanner_cursor.column = 1;                       \
+    }                                                  \
+  while (0)
 
-/* Each time we match a string, move the end cursor to its end. */
-#define STEP  LOCATION_STEP (*loc)
+/* Location of scanner cursor.  */
+boundary scanner_cursor;
 
-static void extend_location (location_t *, char const *, int);
-#define YY_USER_ACTION  extend_location (loc, yytext, yyleng);
+static void adjust_location (location_t *, char const *, size_t);
+#define YY_USER_ACTION  adjust_location (loc, yytext, yyleng);
 
 static size_t no_cr_read (FILE *, char *, size_t);
 #define YY_INPUT(buf, result, size) ((result) = no_cr_read (yyin, buf, size))
@@ -93,13 +97,14 @@ static void handle_dollar (braced_code_t
                           char *cp, location_t location);
 static void handle_at (braced_code_t code_kind,
                       char *cp, location_t location);
-static void handle_syncline (char *args, location_t *location);
+static void handle_syncline (char *args);
 static int convert_ucn_to_byte (char const *hex_text);
-static void unexpected_end_of_file (location_t *, char const *);
+static void unexpected_end_of_file (boundary, char const *);
 
 %}
 %x SC_COMMENT SC_LINE_COMMENT SC_YACC_COMMENT
 %x SC_STRING SC_CHARACTER
+%x SC_AFTER_IDENTIFIER
 %x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
 %x SC_BRACED_CODE SC_PROLOGUE SC_EPILOGUE
 
@@ -122,15 +127,41 @@ splice     (\\[ \f\t\v]*\n)*
   /* Nesting level of the current code in braces.  */
   int braces_level IF_LINT (= 0);
 
-  /* Scanner context when scanning C code.  */
-  int c_context IF_LINT (= 0);
+  /* Parent context state, when applicable.  */
+  int context_state IF_LINT (= 0);
 
-  /* At each yylex invocation, mark the current position as the
-     start of the next token.  */
-  STEP;
+  /* Location of most recent identifier, when applicable.  */
+  location_t id_loc IF_LINT (= *loc);
+
+  /* Location where containing code started, when applicable.  */
+  boundary code_start IF_LINT (= loc->start);
+
+  /* Location where containing comment or string or character literal
+     started, when applicable.  */
+  boundary token_start IF_LINT (= loc->start);
 %}
 
 
+  /*-----------------------.
+  | Scanning white space.  |
+  `-----------------------*/
+
+<INITIAL,SC_AFTER_IDENTIFIER>
+{
+  [ \f\n\t\v]  ;
+
+  /* Comments. */
+  "/*"         token_start = loc->start; context_state = YY_START; BEGIN 
SC_YACC_COMMENT;
+  "//".*       ;
+
+  /* #line directives are not documented, and may be withdrawn or
+     modified in future versions of Bison.  */
+  ^"#line "{int}" \"".*"\"\n" {
+    handle_syncline (yytext + sizeof "#line " - 1);
+  }
+}
+
+
   /*----------------------------.
   | Scanning Bison directives.  |
   `----------------------------*/
@@ -171,32 +202,23 @@ splice     (\\[ \f\t\v]*\n)*
   "%verbose"              return PERCENT_VERBOSE;
   "%yacc"                 return PERCENT_YACC;
 
-  {directive}             {
+  {directive} {
     complain_at (*loc, _("invalid directive: %s"), quote (yytext));
-    STEP;
-  }
-
-  ^"#line "{int}" \"".*"\"\n" {
-    handle_syncline (yytext + sizeof "#line " - 1, loc);
-    STEP;
   }
 
   "="                     return EQUAL;
-  ":"                     rule_length = 0; return COLON;
   "|"                     rule_length = 0; return PIPE;
   ";"                     return SEMICOLON;
 
-  [ \f\n\t\v]  STEP;
-
   "," {
     warn_at (*loc, _("stray `,' treated as white space"));
-    STEP;
   }
 
-  {id}        {
+  {id} {
     val->symbol = symbol_get (yytext, *loc);
+    id_loc = *loc;
     rule_length++;
-    return ID;
+    BEGIN SC_AFTER_IDENTIFIER;
   }
 
   {int} {
@@ -213,20 +235,21 @@ splice     (\\[ \f\t\v]*\n)*
   }
 
   /* Characters.  We don't check there is only one.  */
-  "'"         STRING_GROW; BEGIN SC_ESCAPED_CHARACTER;
+  "'"        STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
 
   /* Strings. */
-  "\""        STRING_GROW; BEGIN SC_ESCAPED_STRING;
-
-  /* Comments. */
-  "/*"        BEGIN SC_YACC_COMMENT;
-  "//".*      STEP;
+  "\""       STRING_GROW; token_start = loc->start; BEGIN SC_ESCAPED_STRING;
 
   /* Prologue. */
-  "%{"        BEGIN SC_PROLOGUE;
+  "%{"        code_start = loc->start; BEGIN SC_PROLOGUE;
 
   /* Code in between braces.  */
-  "{"         STRING_GROW; braces_level = 0; BEGIN SC_BRACED_CODE;
+  "{" {
+    STRING_GROW;
+    braces_level = 0;
+    code_start = loc->start;
+    BEGIN SC_BRACED_CODE;
+  }
 
   /* A type. */
   "<"{tag}">" {
@@ -240,13 +263,42 @@ splice     (\\[ \f\t\v]*\n)*
   "%%" {
     static int percent_percent_count;
     if (++percent_percent_count == 2)
-      BEGIN SC_EPILOGUE;
+      {
+       code_start = loc->start;
+       BEGIN SC_EPILOGUE;
+      }
     return PERCENT_PERCENT;
   }
 
   . {
     complain_at (*loc, _("invalid character: %s"), quote (yytext));
-    STEP;
+  }
+}
+
+
+  /*-----------------------------------------------------------------.
+  | Scanning after an identifier, checking whether a colon is next.  |
+  `-----------------------------------------------------------------*/
+
+<SC_AFTER_IDENTIFIER>
+{
+  ":" {
+    rule_length = 0;
+    *loc = id_loc;
+    BEGIN INITIAL;
+    return ID_COLON;
+  }
+  . {
+    scanner_cursor.column -= mbsnwidth (yytext, yyleng, 0);
+    yyless (0);
+    *loc = id_loc;
+    BEGIN INITIAL;
+    return ID;
+  }
+  <<EOF>> {
+    *loc = id_loc;
+    BEGIN INITIAL;
+    return ID;
   }
 }
 
@@ -257,13 +309,9 @@ splice      (\\[ \f\t\v]*\n)*
 
 <SC_YACC_COMMENT>
 {
-  "*/" {
-    STEP;
-    BEGIN INITIAL;
-  }
-
+  "*/"     BEGIN context_state;
   .|\n    ;
-  <<EOF>>  unexpected_end_of_file (loc, "*/");
+  <<EOF>>  unexpected_end_of_file (token_start, "*/");
 }
 
 
@@ -273,8 +321,8 @@ splice       (\\[ \f\t\v]*\n)*
 
 <SC_COMMENT>
 {
-  "*"{splice}"/"  STRING_GROW; BEGIN c_context;
-  <<EOF>>        unexpected_end_of_file (loc, "*/");
+  "*"{splice}"/"  STRING_GROW; BEGIN context_state;
+  <<EOF>>        unexpected_end_of_file (token_start, "*/");
 }
 
 
@@ -284,9 +332,9 @@ splice       (\\[ \f\t\v]*\n)*
 
 <SC_LINE_COMMENT>
 {
-  "\n"          STRING_GROW; BEGIN c_context;
+  "\n"          STRING_GROW; BEGIN context_state;
   {splice}      STRING_GROW;
-  <<EOF>>       BEGIN c_context;
+  <<EOF>>       BEGIN context_state;
 }
 
 
@@ -300,6 +348,7 @@ splice       (\\[ \f\t\v]*\n)*
   "\"" {
     STRING_GROW;
     STRING_FINISH;
+    loc->start = token_start;
     val->string = last_string;
     rule_length++;
     BEGIN INITIAL;
@@ -307,7 +356,7 @@ splice       (\\[ \f\t\v]*\n)*
   }
 
   .|\n     STRING_GROW;
-  <<EOF>>   unexpected_end_of_file (loc, "\"");
+  <<EOF>>   unexpected_end_of_file (token_start, "\"");
 }
 
   /*---------------------------------------------------------------.
@@ -320,6 +369,7 @@ splice       (\\[ \f\t\v]*\n)*
   "'" {
     STRING_GROW;
     STRING_FINISH;
+    loc->start = token_start;
     val->symbol = symbol_get (last_string, *loc);
     symbol_class_set (val->symbol, token_sym, *loc);
     symbol_user_token_number_set (val->symbol,
@@ -331,7 +381,7 @@ splice       (\\[ \f\t\v]*\n)*
   }
 
   .|\n     STRING_GROW;
-  <<EOF>>   unexpected_end_of_file (loc, "'");
+  <<EOF>>   unexpected_end_of_file (token_start, "'");
 }
 
 
@@ -344,11 +394,7 @@ splice      (\\[ \f\t\v]*\n)*
   \\[0-7]{1,3} {
     unsigned long c = strtoul (yytext + 1, 0, 8);
     if (UCHAR_MAX < c)
-      {
-       complain_at (*loc, _("invalid escape sequence: %s"),
-                    quote (yytext));
-       STEP;
-      }
+      complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
     else
       obstack_1grow (&string_obstack, c);
   }
@@ -358,11 +404,7 @@ splice      (\\[ \f\t\v]*\n)*
     errno = 0;
     c = strtoul (yytext + 2, 0, 16);
     if (UCHAR_MAX < c || errno)
-      {
-       complain_at (*loc, _("invalid escape sequence: %s"),
-                    quote (yytext));
-       STEP;
-      }
+      complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
     else
       obstack_1grow (&string_obstack, c);
   }
@@ -381,17 +423,12 @@ splice     (\\[ \f\t\v]*\n)*
   \\(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));
-       STEP;
-      }
+      complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
     else
       obstack_1grow (&string_obstack, c);
   }
   \\(.|\n)     {
-    complain_at (*loc, _("unrecognized escape sequence: %s"),
-                quote (yytext));
+    complain_at (*loc, _("unrecognized escape sequence: %s"), quote (yytext));
     STRING_GROW;
   }
 }
@@ -404,9 +441,9 @@ splice       (\\[ \f\t\v]*\n)*
 
 <SC_CHARACTER>
 {
-  "'"                  STRING_GROW; BEGIN c_context;
+  "'"                  STRING_GROW; BEGIN context_state;
   address@hidden       STRING_GROW;
-  <<EOF>>              unexpected_end_of_file (loc, "'");
+  <<EOF>>              unexpected_end_of_file (token_start, "'");
 }
 
 
@@ -417,9 +454,9 @@ splice       (\\[ \f\t\v]*\n)*
 
 <SC_STRING>
 {
-  "\""                 STRING_GROW; BEGIN c_context;
+  "\""                 STRING_GROW; BEGIN context_state;
   address@hidden       STRING_GROW;
-  <<EOF>>              unexpected_end_of_file (loc, "\"");
+  <<EOF>>              unexpected_end_of_file (token_start, "\"");
 }
 
 
@@ -429,10 +466,29 @@ splice     (\\[ \f\t\v]*\n)*
 
 <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
 {
-  "'"            STRING_GROW; c_context = YY_START; BEGIN SC_CHARACTER;
-  "\""           STRING_GROW; c_context = YY_START; BEGIN SC_STRING;
-  "/"{splice}"*"  STRING_GROW; c_context = YY_START; BEGIN SC_COMMENT;
-  "/"{splice}"/"  STRING_GROW; c_context = YY_START; BEGIN SC_LINE_COMMENT;
+  "'" {
+    STRING_GROW;
+    context_state = YY_START;
+    token_start = loc->start;
+    BEGIN SC_CHARACTER;
+  }
+  "\"" {
+    STRING_GROW;
+    context_state = YY_START;
+    token_start = loc->start;
+    BEGIN SC_STRING;
+  }
+  "/"{splice}"*" {
+    STRING_GROW;
+    context_state = YY_START;
+    token_start = loc->start;
+    BEGIN SC_COMMENT;
+  }
+  "/"{splice}"/" {
+    STRING_GROW;
+    context_state = YY_START;
+    BEGIN SC_LINE_COMMENT;
+  }
 }
 
 
@@ -451,6 +507,7 @@ splice       (\\[ \f\t\v]*\n)*
     if (braces_level < 0)
       {
        STRING_FINISH;
+       loc->start = code_start;
        val->string = last_string;
        rule_length++;
        BEGIN INITIAL;
@@ -467,7 +524,7 @@ splice       (\\[ \f\t\v]*\n)*
   "@"(-?[0-9]+|"$")               { handle_at (current_braced_code,
                                               yytext, *loc); }
 
-  <<EOF>>  unexpected_end_of_file (loc, "}");
+  <<EOF>>  unexpected_end_of_file (code_start, "}");
 }
 
 
@@ -479,12 +536,13 @@ splice     (\\[ \f\t\v]*\n)*
 {
   "%}" {
     STRING_FINISH;
+    loc->start = code_start;
     val->string = last_string;
     BEGIN INITIAL;
     return PROLOGUE;
   }
 
-  <<EOF>>  unexpected_end_of_file (loc, "%}");
+  <<EOF>>  unexpected_end_of_file (code_start, "%}");
 }
 
 
@@ -497,6 +555,7 @@ splice       (\\[ \f\t\v]*\n)*
 {
   <<EOF>> {
     STRING_FINISH;
+    loc->start = code_start;
     val->string = last_string;
     BEGIN INITIAL;
     return EPILOGUE;
@@ -521,24 +580,23 @@ splice     (\\[ \f\t\v]*\n)*
 
 %%
 
-/* Extend *LOC to account for token TOKEN of size SIZE.  */
+/* Set *LOC and adjust scanner cursor to account for token TOKEN of
+   size SIZE.  */
 
 static void
-extend_location (location_t *loc, char const *token, int size)
+adjust_location (location_t *loc, char const *token, size_t size)
 {
-  int line = loc->last_line;
-  int column = loc->last_column;
+  int line = scanner_cursor.line;
+  int column = scanner_cursor.column;
   char const *p0 = token;
   char const *p = token;
   char const *lim = token + size;
 
+  loc->start = scanner_cursor;
+
   for (p = token; p < lim; p++)
     switch (*p)
       {
-      case '\r':
-       /* \r shouldn't survive no_cr_read.  */
-       abort ();
-
       case '\n':
        line++;
        column = 1;
@@ -552,8 +610,10 @@ extend_location (location_t *loc, char c
        break;
       }
 
-  loc->last_line = line;
-  loc->last_column = column + mbsnwidth (p0, p - p0, 0);
+  scanner_cursor.line = line;
+  scanner_cursor.column = column + mbsnwidth (p0, p - p0, 0);
+
+  loc->end = scanner_cursor;
 }
 
 
@@ -839,34 +899,37 @@ convert_ucn_to_byte (char const *ucn)
 `----------------------------------------------------------------*/
 
 static void
-handle_syncline (char *args, location_t *location)
+handle_syncline (char *args)
 {
   int lineno = strtol (args, &args, 10);
   const char *file = NULL;
   file = strchr (args, '"') + 1;
   *strchr (file, '"') = 0;
-  current_file = xstrdup (file);
-  location->file = current_file;
-  location->last_line = lineno;
+  scanner_cursor.file = current_file = xstrdup (file);
+  scanner_cursor.line = lineno;
+  scanner_cursor.column = 1;
 }
 
 
-/*-------------------------------------------------------------.
-| Report an unexpected end of file at LOC.  An end of file was |
-| encountered and the expected TOKEN_END was missing.  After   |
-| reporting the problem, pretend that TOKEN_END was found.     |
-`-------------------------------------------------------------*/
+/*------------------------------------------------------------------------.
+| Report an unexpected EOF in a token or comment starting at START.       |
+| An end of file was encountered and the expected TOKEN_END was missing.  |
+| After reporting the problem, pretend that TOKEN_END was found.          |
+`------------------------------------------------------------------------*/
 
 static void
-unexpected_end_of_file (location_t *loc, char const *token_end)
+unexpected_end_of_file (boundary start, char const *token_end)
 {
   size_t i = strlen (token_end);
 
-  complain_at (*loc, _("missing `%s' at end of file"), token_end);
-
-  /* Adjust location's last column so that any later message does not
-     mention the characters just inserted.  */
-  loc->last_column -= i;
+  location_t location;
+  location.start = start;
+  location.end = scanner_cursor;
+  complain_at (location, _("missing `%s' at end of file"), token_end);
+
+  /* Adjust scanner cursor so that any later message does not count
+     the characters about to be inserted.  */
+  scanner_cursor.column -= i;
 
   while (i != 0)
     unput (token_end[--i]);
Index: tests/conflicts.at
===================================================================
RCS file: /cvsroot/bison/bison/tests/conflicts.at,v
retrieving revision 1.21
diff -p -u -r1.21 conflicts.at
--- tests/conflicts.at  15 Nov 2002 20:32:21 -0000      1.21
+++ tests/conflicts.at  7 Dec 2002 05:41:59 -0000
@@ -38,7 +38,7 @@ e: 'e' | /* Nothing. */;
 ]])
 
 AT_CHECK([bison -o input.c input.y], 0, [],
-[[input.y:4.8: warning: rule never reduced because of conflicts: e: /* empty */
+[[input.y:4.9: warning: rule never reduced because of conflicts: e: /* empty */
 ]])
 
 AT_CLEANUP
@@ -370,7 +370,7 @@ id : '0';
 
 AT_CHECK([bison -o input.c --report=all input.y], 0, [],
 [[input.y: warning: 1 reduce/reduce conflict
-input.y:4.4-8: warning: rule never reduced because of conflicts: id: '0'
+input.y:4.6-8: warning: rule never reduced because of conflicts: id: '0'
 ]])
 
 # Check the contents of the report.
Index: tests/input.at
===================================================================
RCS file: /cvsroot/bison/bison/tests/input.at,v
retrieving revision 1.22
diff -p -u -r1.22 input.at
--- tests/input.at      30 Nov 2002 09:51:50 -0000      1.22
+++ tests/input.at      7 Dec 2002 05:41:59 -0000
@@ -33,7 +33,7 @@ exp: { $$ = $1 ; };
 ]])
 
 AT_CHECK([bison input.y], [1], [],
-[[input.y:2.6-14: integer out of range: `$1'
+[[input.y:2.13-14: integer out of range: `$1'
 ]])
 
 AT_CLEANUP
@@ -51,7 +51,7 @@ exp: { @$ = @1 ; };
 ]])
 
 AT_CHECK([bison input.y], [1], [],
-[[input.y:2.6-14: integer out of range: address@hidden'
+[[input.y:2.13-14: integer out of range: address@hidden'
 ]])
 
 AT_CLEANUP
@@ -74,9 +74,9 @@ exp: foo {} foo
 ]])
 
 AT_CHECK([bison input.y], [], [],
-[[input.y:4.4-15: warning: type clash on default action: <bar> != <>
-input.y:5.4-8: warning: type clash on default action: <bar> != <>
-input.y:6.4: warning: empty rule for typed nonterminal, and no action
+[[input.y:4.6-15: warning: type clash on default action: <bar> != <>
+input.y:5.6-8: warning: type clash on default action: <bar> != <>
+input.y:6.5: warning: empty rule for typed nonterminal, and no action
 ]])
 
 AT_CLEANUP
Index: tests/reduce.at
===================================================================
RCS file: /cvsroot/bison/bison/tests/reduce.at,v
retrieving revision 1.12
diff -p -u -r1.12 reduce.at
--- tests/reduce.at     2 Aug 2002 08:05:01 -0000       1.12
+++ tests/reduce.at     7 Dec 2002 05:41:59 -0000
@@ -1,5 +1,5 @@
 # Exercising Bison Grammar Reduction.                      -*- Autotest -*-
-# Copyright 2001 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -154,15 +154,15 @@ input.y:11.1-8: warning: useless nonterm
 input.y:12.1-8: warning: useless nonterminal: useless7
 input.y:13.1-8: warning: useless nonterminal: useless8
 input.y:14.1-8: warning: useless nonterminal: useless9
-input.y:6.9-13: warning: useless rule: useless1: '1'
-input.y:7.9-13: warning: useless rule: useless2: '2'
-input.y:8.9-13: warning: useless rule: useless3: '3'
-input.y:9.9-13: warning: useless rule: useless4: '4'
-input.y:10.9-13: warning: useless rule: useless5: '5'
-input.y:11.9-13: warning: useless rule: useless6: '6'
-input.y:12.9-13: warning: useless rule: useless7: '7'
-input.y:13.9-13: warning: useless rule: useless8: '8'
-input.y:14.9-13: warning: useless rule: useless9: '9'
+input.y:6.11-13: warning: useless rule: useless1: '1'
+input.y:7.11-13: warning: useless rule: useless2: '2'
+input.y:8.11-13: warning: useless rule: useless3: '3'
+input.y:9.11-13: warning: useless rule: useless4: '4'
+input.y:10.11-13: warning: useless rule: useless5: '5'
+input.y:11.11-13: warning: useless rule: useless6: '6'
+input.y:12.11-13: warning: useless rule: useless7: '7'
+input.y:13.11-13: warning: useless rule: useless8: '8'
+input.y:14.11-13: warning: useless rule: useless9: '9'
 ]])
 
 AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
@@ -242,9 +242,9 @@ AT_CHECK([[bison not-reduced.y]], 0, [],
 [[not-reduced.y: warning: 2 useless nonterminals and 3 useless rules
 not-reduced.y:14.1-13: warning: useless nonterminal: not_reachable
 not-reduced.y:11.6-19: warning: useless nonterminal: non_productive
-not-reduced.y:11.4-57: warning: useless rule: exp: non_productive
-not-reduced.y:14.14-56: warning: useless rule: not_reachable: useful
-not-reduced.y:17.15-18.63: warning: useless rule: non_productive: 
non_productive useless_token
+not-reduced.y:11.6-57: warning: useless rule: exp: non_productive
+not-reduced.y:14.16-56: warning: useless rule: not_reachable: useful
+not-reduced.y:17.17-18.63: warning: useless rule: non_productive: 
non_productive useless_token
 ]])
 
 AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' not-reduced.output]], 0,
@@ -316,9 +316,9 @@ AT_CHECK([[bison input.y]], 0, [],
 [[input.y: warning: 2 useless nonterminals and 3 useless rules
 input.y:5.15-25: warning: useless nonterminal: underivable
 input.y:6.14-24: warning: useless nonterminal: indirection
-input.y:5.13-25: warning: useless rule: exp: underivable
-input.y:6.12-24: warning: useless rule: underivable: indirection
-input.y:7.12-24: warning: useless rule: indirection: underivable
+input.y:5.15-25: warning: useless rule: exp: underivable
+input.y:6.14-24: warning: useless rule: underivable: indirection
+input.y:7.14-24: warning: useless rule: indirection: underivable
 ]])
 
 AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
Index: tests/regression.at
===================================================================
RCS file: /cvsroot/bison/bison/tests/regression.at,v
retrieving revision 1.76
diff -p -u -r1.76 regression.at
--- tests/regression.at 15 Nov 2002 20:32:21 -0000      1.76
+++ tests/regression.at 7 Dec 2002 05:41:59 -0000
@@ -298,7 +298,7 @@ input.y:5.1-17: invalid directive: `%a-d
 input.y:6.1: invalid character: `%'
 input.y:6.2: invalid character: `-'
 input.y:7.1-8.0: missing `%}' at end of file
-input.y:7.1-8.0: syntax error, unexpected "%{...%}", expecting ";" or "|"
+input.y:7.1-8.0: syntax error, unexpected "%{...%}"
 ]])
 
 AT_CLEANUP




reply via email to

[Prev in Thread] Current Thread [Next in Thread]