Improve selection parsing error reporting
authorTeemu Murtola <teemu.murtola@gmail.com>
Sun, 2 Nov 2014 13:45:21 +0000 (15:45 +0200)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Fri, 5 Dec 2014 15:44:31 +0000 (16:44 +0100)
Now the selection parser tracks the part of selection text that
contributes to the current parsing context, and uses that for more
useful error messages.  At least in some cases, there is now also
context information for syntax errors, although this could likely be
improved further.

Exception handling during selection parsing is also improved:
 - The above context is now added to the exception, similar to what the
   old reporting mechanism does.
 - The full selection is added to the exception as context, also for
   non-interactive parsing.
 - More consistent exception handling, e.g., in cases where an exception
   is thrown during error handling.

Improve documentation for related functions.

Part of #655.

Change-Id: Ib276ce4e219692c9819e45a1637e3660d958803f

14 files changed:
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.h
src/gromacs/selection/parser.patch
src/gromacs/selection/parser.y
src/gromacs/selection/parser_internal.h
src/gromacs/selection/parsetree.cpp
src/gromacs/selection/parsetree.h
src/gromacs/selection/scanner.cpp
src/gromacs/selection/scanner.h
src/gromacs/selection/scanner.l
src/gromacs/selection/scanner_internal.cpp
src/gromacs/selection/scanner_internal.h
src/gromacs/selection/selectioncollection.cpp
src/gromacs/selection/selelem.h

index c2a21dc220515890b9afac9ffc5b63f761c754a9..6a2e337a630f74387044e5587e7cb01292d247d8 100644 (file)
@@ -89,6 +89,7 @@
 #define yychar          _gmx_sel_yychar
 #define yydebug         _gmx_sel_yydebug
 #define yynerrs         _gmx_sel_yynerrs
+#define yylloc          _gmx_sel_yylloc
 
 /* Copy the first part of user declarations.  */
 /* Line 371 of yacc.c  */
@@ -113,7 +114,7 @@ using gmx::SelectionTreeElementPointer;
 #endif
 
 /* Line 371 of yacc.c  */
-#line 117 "parser.cpp"
+#line 118 "parser.cpp"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -187,9 +188,11 @@ extern int _gmx_sel_yydebug;
 #include "parsetree.h"
 #include "selelem.h"
 
+#define YYLTYPE ::gmx::SelectionLocation
+
 
 /* Line 387 of yacc.c  */
-#line 193 "parser.cpp"
+#line 196 "parser.cpp"
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -236,7 +239,7 @@ extern int _gmx_sel_yydebug;
 typedef union YYSTYPE
 {
 /* Line 387 of yacc.c  */
-#line 81 "parser.y"
+#line 83 "parser.y"
 
     int                         i;
     real                        r;
@@ -253,13 +256,26 @@ typedef union YYSTYPE
 
 
 /* Line 387 of yacc.c  */
-#line 257 "parser.cpp"
+#line 260 "parser.cpp"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
 
 #ifndef YYPUSH_MORE_DEFINED
 # define YYPUSH_MORE_DEFINED
@@ -269,7 +285,7 @@ enum { YYPUSH_MORE = 4 };
 typedef struct _gmx_sel_yypstate _gmx_sel_yypstate;
 
 #if defined __STDC__ || defined __cplusplus
-int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, void *scanner);
+int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, YYLTYPE *pushed_loc, void *scanner);
 #else
 int _gmx_sel_yypush_parse ();
 #endif
@@ -290,7 +306,7 @@ void _gmx_sel_yypstate_delete ();
 /* Copy the second part of user declarations.  */
 
 /* Line 390 of yacc.c  */
-#line 294 "parser.cpp"
+#line 310 "parser.cpp"
 
 #ifdef short
 # undef short
@@ -432,14 +448,16 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 
 
 #if (! defined yyoverflow \
-     && (! defined __cplusplus \
-        || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+     && (! defined __cplusplus || defined GMX_YYFORCE_C_STACK_EXTENSION \
+        || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+            && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
   yytype_int16 yyss_alloc;
   YYSTYPE yyvs_alloc;
+  YYLTYPE yyls_alloc;
 };
 
 /* The size of the maximum gap between one aligned stack and the next.  */
@@ -448,8 +466,8 @@ union yyalloc
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+      + 2 * YYSTACK_GAP_MAXIMUM)
 
 # define YYCOPY_NEEDED 1
 
@@ -598,16 +616,16 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   196,   196,   201,   212,   213,   235,   240,   251,   263,
-     269,   276,   283,   290,   300,   301,   308,   309,   323,   324,
-     328,   329,   332,   333,   336,   337,   345,   356,   367,   378,
-     382,   393,   400,   409,   410,   415,   416,   417,   421,   429,
-     437,   445,   456,   471,   482,   496,   504,   512,   523,   529,
-     535,   541,   547,   553,   559,   566,   577,   592,   601,   605,
-     615,   629,   637,   645,   658,   660,   666,   671,   682,   691,
-     692,   697,   702,   710,   721,   722,   726,   732,   740,   750,
-     756,   762,   768,   774,   778,   784,   790,   797,   801,   807,
-     813
+       0,   199,   199,   204,   215,   216,   236,   241,   252,   264,
+     270,   277,   284,   291,   301,   302,   309,   310,   324,   325,
+     329,   330,   333,   334,   337,   338,   346,   357,   368,   379,
+     383,   394,   401,   410,   411,   416,   417,   418,   422,   430,
+     438,   446,   457,   472,   483,   497,   505,   513,   524,   530,
+     536,   542,   548,   554,   560,   567,   578,   593,   602,   606,
+     616,   630,   638,   646,   659,   661,   667,   672,   683,   692,
+     693,   698,   703,   711,   722,   723,   727,   733,   741,   751,
+     757,   763,   769,   775,   779,   785,   791,   798,   802,   808,
+     814
 };
 #endif
 
@@ -895,7 +913,7 @@ do                                                              \
     }                                                           \
   else                                                          \
     {                                                           \
-      yyerror (scanner, YY_("syntax error: cannot back up")); \
+      yyerror (&yylloc, scanner, YY_("syntax error: cannot back up")); \
       YYERROR;                                                 \
     }                                                          \
 while (YYID (0))
@@ -905,17 +923,90 @@ while (YYID (0))
 #define YYERRCODE      256
 
 
-/* This macro is provided for backward compatibility. */
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (YYID (N))                                                     \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
+    while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
 #ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static unsigned
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+#else
+static unsigned
+yy_location_print_ (yyo, yylocp)
+    FILE *yyo;
+    YYLTYPE const * const yylocp;
+#endif
+{
+  unsigned res = 0;
+  int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+  if (0 <= yylocp->first_line)
+    {
+      res += fprintf (yyo, "%d", yylocp->first_line);
+      if (0 <= yylocp->first_column)
+        res += fprintf (yyo, ".%d", yylocp->first_column);
+    }
+  if (0 <= yylocp->last_line)
+    {
+      if (yylocp->first_line < yylocp->last_line)
+        {
+          res += fprintf (yyo, "-%d", yylocp->last_line);
+          if (0 <= end_col)
+            res += fprintf (yyo, ".%d", end_col);
+        }
+      else if (0 <= end_col && yylocp->first_column < end_col)
+        res += fprintf (yyo, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  yy_location_print_ (File, &(Loc))
+
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
 #endif
 
 
 /* YYLEX -- calling `yylex' with the right arguments.  */
 #ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, YYLEX_PARAM)
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
 #else
-# define YYLEX yylex (&yylval)
+# define YYLEX yylex (&yylval, &yylloc)
 #endif
 
 /* Enable debugging if requested.  */
@@ -938,7 +1029,7 @@ do {                                                                         \
     {                                                                    \
       YYFPRINTF (stderr, "%s ", Title);                                          \
       yy_symbol_print (stderr,                                           \
-                 Type, Value, scanner); \
+                 Type, Value, Location, scanner); \
       YYFPRINTF (stderr, "\n");                                                  \
     }                                                                    \
 } while (YYID (0))
@@ -952,13 +1043,14 @@ do {                                                                       \
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner)
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
 #else
 static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner)
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
     void *scanner;
 #endif
 {
@@ -966,6 +1058,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner)
   YYUSE (yyo);
   if (!yyvaluep)
     return;
+  YYUSE (yylocationp);
   YYUSE (scanner);
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
@@ -984,13 +1077,14 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner)
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *scanner)
 #else
 static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, scanner)
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, scanner)
     FILE *yyoutput;
     int yytype;
     YYSTYPE const * const yyvaluep;
+    YYLTYPE const * const yylocationp;
     void *scanner;
 #endif
 {
@@ -999,7 +1093,9 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, scanner)
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner);
+  YY_LOCATION_PRINT (yyoutput, *yylocationp);
+  YYFPRINTF (yyoutput, ": ");
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, scanner);
   YYFPRINTF (yyoutput, ")");
 }
 
@@ -1042,11 +1138,12 @@ do {                                                            \
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule, void *scanner)
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *scanner)
 #else
 static void
-yy_reduce_print (yyvsp, yyrule, scanner)
+yy_reduce_print (yyvsp, yylsp, yyrule, scanner)
     YYSTYPE *yyvsp;
+    YYLTYPE *yylsp;
     int yyrule;
     void *scanner;
 #endif
@@ -1062,7 +1159,7 @@ yy_reduce_print (yyvsp, yyrule, scanner)
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
                       &(yyvsp[(yyi + 1) - (yynrhs)])
-                                      , scanner);
+                      , &(yylsp[(yyi + 1) - (yynrhs)])                , scanner);
       YYFPRINTF (stderr, "\n");
     }
 }
@@ -1070,7 +1167,7 @@ yy_reduce_print (yyvsp, yyrule, scanner)
 # define YY_REDUCE_PRINT(Rule)         \
 do {                                   \
   if (yydebug)                         \
-    yy_reduce_print (yyvsp, Rule, scanner); \
+    yy_reduce_print (yyvsp, yylsp, Rule, scanner); \
 } while (YYID (0))
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
@@ -1350,17 +1447,19 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *scanner)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, void *scanner)
 #else
 static void
-yydestruct (yymsg, yytype, yyvaluep, scanner)
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, scanner)
     const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
+    YYLTYPE *yylocationp;
     void *scanner;
 #endif
 {
   YYUSE (yyvaluep);
+  YYUSE (yylocationp);
   YYUSE (scanner);
 
   if (!yymsg)
@@ -1371,178 +1470,178 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
     {
       case 6: /* STR */
 /* Line 1393 of yacc.c  */
-#line 176 "parser.y"
+#line 178 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1378 "parser.cpp"
+#line 1477 "parser.cpp"
         break;
       case 7: /* IDENTIFIER */
 /* Line 1393 of yacc.c  */
-#line 176 "parser.y"
+#line 178 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1385 "parser.cpp"
+#line 1484 "parser.cpp"
         break;
       case 16: /* KEYWORD_POS */
 /* Line 1393 of yacc.c  */
-#line 176 "parser.y"
+#line 178 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1392 "parser.cpp"
+#line 1491 "parser.cpp"
         break;
       case 23: /* PARAM */
 /* Line 1393 of yacc.c  */
-#line 177 "parser.y"
+#line 179 "parser.y"
         { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
 /* Line 1393 of yacc.c  */
-#line 1399 "parser.cpp"
+#line 1498 "parser.cpp"
         break;
       case 26: /* CMP_OP */
 /* Line 1393 of yacc.c  */
-#line 176 "parser.y"
+#line 178 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1406 "parser.cpp"
+#line 1505 "parser.cpp"
         break;
       case 50: /* commands */
 /* Line 1393 of yacc.c  */
-#line 178 "parser.y"
+#line 180 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1413 "parser.cpp"
+#line 1512 "parser.cpp"
         break;
       case 51: /* command */
 /* Line 1393 of yacc.c  */
-#line 178 "parser.y"
+#line 180 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1420 "parser.cpp"
+#line 1519 "parser.cpp"
         break;
       case 52: /* cmd_plain */
 /* Line 1393 of yacc.c  */
-#line 178 "parser.y"
+#line 180 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1427 "parser.cpp"
+#line 1526 "parser.cpp"
         break;
       case 53: /* selection */
 /* Line 1393 of yacc.c  */
-#line 178 "parser.y"
+#line 180 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1434 "parser.cpp"
+#line 1533 "parser.cpp"
         break;
       case 57: /* string */
 /* Line 1393 of yacc.c  */
-#line 176 "parser.y"
+#line 178 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1441 "parser.cpp"
+#line 1540 "parser.cpp"
         break;
       case 58: /* sel_expr */
 /* Line 1393 of yacc.c  */
-#line 179 "parser.y"
+#line 181 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1448 "parser.cpp"
+#line 1547 "parser.cpp"
         break;
       case 59: /* pos_mod */
 /* Line 1393 of yacc.c  */
-#line 177 "parser.y"
+#line 179 "parser.y"
         { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
 /* Line 1393 of yacc.c  */
-#line 1455 "parser.cpp"
+#line 1554 "parser.cpp"
         break;
       case 61: /* num_expr */
 /* Line 1393 of yacc.c  */
-#line 179 "parser.y"
+#line 181 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1462 "parser.cpp"
+#line 1561 "parser.cpp"
         break;
       case 62: /* str_expr */
 /* Line 1393 of yacc.c  */
-#line 179 "parser.y"
+#line 181 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1469 "parser.cpp"
+#line 1568 "parser.cpp"
         break;
       case 63: /* pos_expr */
 /* Line 1393 of yacc.c  */
-#line 179 "parser.y"
+#line 181 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1476 "parser.cpp"
+#line 1575 "parser.cpp"
         break;
       case 64: /* method_params */
 /* Line 1393 of yacc.c  */
-#line 180 "parser.y"
+#line 182 "parser.y"
         { delete ((*yyvaluep).plist);       };
 /* Line 1393 of yacc.c  */
-#line 1483 "parser.cpp"
+#line 1582 "parser.cpp"
         break;
       case 65: /* method_param_list */
 /* Line 1393 of yacc.c  */
-#line 180 "parser.y"
+#line 182 "parser.y"
         { delete ((*yyvaluep).plist);       };
 /* Line 1393 of yacc.c  */
-#line 1490 "parser.cpp"
+#line 1589 "parser.cpp"
         break;
       case 66: /* method_param */
 /* Line 1393 of yacc.c  */
-#line 180 "parser.y"
+#line 182 "parser.y"
         { delete ((*yyvaluep).param);       };
 /* Line 1393 of yacc.c  */
-#line 1497 "parser.cpp"
+#line 1596 "parser.cpp"
         break;
       case 67: /* value_list */
 /* Line 1393 of yacc.c  */
-#line 181 "parser.y"
+#line 183 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1504 "parser.cpp"
+#line 1603 "parser.cpp"
         break;
       case 68: /* value_list_contents */
 /* Line 1393 of yacc.c  */
-#line 181 "parser.y"
+#line 183 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1511 "parser.cpp"
+#line 1610 "parser.cpp"
         break;
       case 69: /* basic_value_list */
 /* Line 1393 of yacc.c  */
-#line 181 "parser.y"
+#line 183 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1518 "parser.cpp"
+#line 1617 "parser.cpp"
         break;
       case 70: /* basic_value_list_contents */
 /* Line 1393 of yacc.c  */
-#line 181 "parser.y"
+#line 183 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1525 "parser.cpp"
+#line 1624 "parser.cpp"
         break;
       case 71: /* value_item */
 /* Line 1393 of yacc.c  */
-#line 182 "parser.y"
+#line 184 "parser.y"
         { delete ((*yyvaluep).val);       };
 /* Line 1393 of yacc.c  */
-#line 1532 "parser.cpp"
+#line 1631 "parser.cpp"
         break;
       case 72: /* basic_value_item */
 /* Line 1393 of yacc.c  */
-#line 182 "parser.y"
+#line 184 "parser.y"
         { delete ((*yyvaluep).val);       };
 /* Line 1393 of yacc.c  */
-#line 1539 "parser.cpp"
+#line 1638 "parser.cpp"
         break;
       case 73: /* value_item_range */
 /* Line 1393 of yacc.c  */
-#line 182 "parser.y"
+#line 184 "parser.y"
         { delete ((*yyvaluep).val);       };
 /* Line 1393 of yacc.c  */
-#line 1546 "parser.cpp"
+#line 1645 "parser.cpp"
         break;
 
       default:
@@ -1564,6 +1663,7 @@ struct yypstate
     /* The stacks and their tools:
        `yyss': related to states.
        `yyvs': related to semantic values.
+       `yyls': related to locations.
 
        Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
@@ -1578,6 +1678,14 @@ struct yypstate
     YYSTYPE *yyvs;
     YYSTYPE *yyvsp;
 
+    /* The location stack.  */
+    YYLTYPE yylsa[YYINITDEPTH];
+    YYLTYPE *yyls;
+    YYLTYPE *yylsp;
+
+    /* The locations where the error started and ended.  */
+    YYLTYPE yyerror_range[3];
+
     YYSIZE_T yystacksize;
     /* Used to determine if this is the first time this instance has
        been used.  */
@@ -1631,6 +1739,10 @@ yypstate_delete (yyps)
 #define yyvsa yyps->yyvsa
 #define yyvs yyps->yyvs
 #define yyvsp yyps->yyvsp
+#define yylsa yyps->yylsa
+#define yyls yyps->yyls
+#define yylsp yyps->yylsp
+#define yyerror_range yyps->yyerror_range
 #define yystacksize yyps->yystacksize
 
 
@@ -1641,13 +1753,14 @@ yypstate_delete (yyps)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 int
-yypush_parse (yypstate *yyps, int yypushed_char, YYSTYPE const *yypushed_val, void *scanner)
+yypush_parse (yypstate *yyps, int yypushed_char, YYSTYPE const *yypushed_val, YYLTYPE *yypushed_loc, void *scanner)
 #else
 int
-yypush_parse (yyps, yypushed_char, yypushed_val, scanner)
+yypush_parse (yyps, yypushed_char, yypushed_val, yypushed_loc, scanner)
     yypstate *yyps;
     int yypushed_char;
     YYSTYPE const *yypushed_val;
+    YYLTYPE *yypushed_loc;
     void *scanner;
 #endif
 {
@@ -1669,6 +1782,11 @@ int yychar;
 static YYSTYPE yyval_default;
 # define YY_INITIAL_VALUE(Value) = Value
 #endif
+static YYLTYPE yyloc_default
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
 #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
 # define YY_IGNORE_MAYBE_UNINITIALIZED_END
@@ -1680,6 +1798,10 @@ static YYSTYPE yyval_default;
 /* The semantic value of the lookahead symbol.  */
 YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
 
+/* Location data for the lookahead symbol.  */
+YYLTYPE yylloc = yyloc_default;
+
+
   int yyn;
   int yyresult;
   /* Lookahead token as an internal (translated) token number.  */
@@ -1687,6 +1809,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
+  YYLTYPE yyloc;
 
 #if YYERROR_VERBOSE
   /* Buffer for error messages, and its allocated size.  */
@@ -1695,7 +1818,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
   YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
 #endif
 
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
 
   /* The number of symbols on the RHS of the reduced rule.
      Keep to zero when no symbol should be popped.  */
@@ -1709,6 +1832,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
 
   yyssp = yyss = yyssa;
   yyvsp = yyvs = yyvsa;
+  yylsp = yyls = yylsa;
   yystacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1717,6 +1841,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
   yyerrstatus = 0;
   yynerrs = 0;
   yychar = YYEMPTY; /* Cause a token to be read.  */
+  yylsp[0] = *yypushed_loc;
   goto yysetstate;
 
 /*------------------------------------------------------------.
@@ -1742,6 +1867,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
           memory.  */
        YYSTYPE *yyvs1 = yyvs;
        yytype_int16 *yyss1 = yyss;
+       YYLTYPE *yyls1 = yyls;
 
        /* Each stack pointer address is followed by the size of the
           data in use in that stack, in bytes.  This used to be a
@@ -1750,8 +1876,10 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
        yyoverflow (YY_("memory exhausted"),
                    &yyss1, yysize * sizeof (*yyssp),
                    &yyvs1, yysize * sizeof (*yyvsp),
+                   &yyls1, yysize * sizeof (*yylsp),
                    &yystacksize);
 
+       yyls = yyls1;
        yyss = yyss1;
        yyvs = yyvs1;
       }
@@ -1774,6 +1902,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
          goto yyexhaustedlab;
        YYSTACK_RELOCATE (yyss_alloc, yyss);
        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+       YYSTACK_RELOCATE (yyls_alloc, yyls);
 #  undef YYSTACK_RELOCATE
        if (yyss1 != yyssa)
          YYSTACK_FREE (yyss1);
@@ -1783,6 +1912,7 @@ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
 
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
+      yylsp = yyls + yysize - 1;
 
       YYDPRINTF ((stderr, "Stack size increased to %lu\n",
                  (unsigned long int) yystacksize));
@@ -1828,6 +1958,8 @@ yyread_pushed_token:
       yychar = yypushed_char;
       if (yypushed_val)
         yylval = *yypushed_val;
+      if (yypushed_loc)
+        yylloc = *yypushed_loc;
     }
 
   if (yychar <= YYEOF)
@@ -1870,7 +2002,7 @@ yyread_pushed_token:
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
-
+  *++yylsp = yylloc;
   goto yynewstate;
 
 
@@ -1901,63 +2033,62 @@ yyreduce:
      GCC warning that YYVAL may be used uninitialized.  */
   yyval = yyvsp[1-yylen];
 
-
+  /* Default location.  */
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
         case 2:
 /* Line 1787 of yacc.c  */
-#line 196 "parser.y"
+#line 199 "parser.y"
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
-                 END_ACTION;
+                 END_ACTION_TOPLEVEL;
              }
     break;
 
   case 3:
 /* Line 1787 of yacc.c  */
-#line 202 "parser.y"
+#line 205 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_append_selection(get((yyvsp[(2) - (2)].sel)), get((yyvsp[(1) - (2)].sel)), scanner));
                  if (_gmx_sel_parser_should_finish(scanner))
                      YYACCEPT;
-                 END_ACTION;
+                 END_ACTION_TOPLEVEL;
              }
     break;
 
   case 4:
 /* Line 1787 of yacc.c  */
-#line 212 "parser.y"
+#line 215 "parser.y"
     { (yyval.sel) = (yyvsp[(1) - (2)].sel); }
     break;
 
   case 5:
 /* Line 1787 of yacc.c  */
-#line 214 "parser.y"
+#line 217 "parser.y"
     {
                  BEGIN_ACTION;
-                 _gmx_selparser_error(scanner, "invalid selection '%s'",
-                                      _gmx_sel_lexer_pselstr(scanner));
                  _gmx_sel_lexer_clear_method_stack(scanner);
-                 if (_gmx_sel_is_lexer_interactive(scanner))
+                 if (_gmx_selparser_handle_error(scanner))
                  {
-                     _gmx_sel_lexer_clear_pselstr(scanner);
                      yyerrok;
                  }
                  else
                  {
                      YYABORT;
                  }
+                 _gmx_sel_lexer_clear_pselstr(scanner);
                  set_empty((yyval.sel));
-                 END_ACTION;
+                 END_ACTION_TOPLEVEL;
              }
     break;
 
   case 6:
 /* Line 1787 of yacc.c  */
-#line 235 "parser.y"
+#line 236 "parser.y"
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
@@ -1967,7 +2098,7 @@ yyreduce:
 
   case 7:
 /* Line 1787 of yacc.c  */
-#line 241 "parser.y"
+#line 242 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer s
@@ -1982,7 +2113,7 @@ yyreduce:
 
   case 8:
 /* Line 1787 of yacc.c  */
-#line 252 "parser.y"
+#line 253 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(1) - (1)].str));
@@ -1998,7 +2129,7 @@ yyreduce:
 
   case 9:
 /* Line 1787 of yacc.c  */
-#line 264 "parser.y"
+#line 265 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[(1) - (1)].sel)), scanner));
@@ -2008,7 +2139,7 @@ yyreduce:
 
   case 10:
 /* Line 1787 of yacc.c  */
-#line 270 "parser.y"
+#line 271 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(1) - (2)].str));
@@ -2019,7 +2150,7 @@ yyreduce:
 
   case 11:
 /* Line 1787 of yacc.c  */
-#line 277 "parser.y"
+#line 278 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2030,7 +2161,7 @@ yyreduce:
 
   case 12:
 /* Line 1787 of yacc.c  */
-#line 284 "parser.y"
+#line 285 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2041,7 +2172,7 @@ yyreduce:
 
   case 13:
 /* Line 1787 of yacc.c  */
-#line 291 "parser.y"
+#line 292 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2052,13 +2183,13 @@ yyreduce:
 
   case 14:
 /* Line 1787 of yacc.c  */
-#line 300 "parser.y"
+#line 301 "parser.y"
     { (yyval.sel) = (yyvsp[(1) - (1)].sel); }
     break;
 
   case 15:
 /* Line 1787 of yacc.c  */
-#line 302 "parser.y"
+#line 303 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(1) - (1)].sel)), NULL, scanner));
@@ -2069,13 +2200,13 @@ yyreduce:
 
   case 16:
 /* Line 1787 of yacc.c  */
-#line 308 "parser.y"
+#line 309 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 17:
 /* Line 1787 of yacc.c  */
-#line 310 "parser.y"
+#line 311 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), get((yyvsp[(1) - (3)].sel)), scanner));
@@ -2086,55 +2217,55 @@ yyreduce:
 
   case 18:
 /* Line 1787 of yacc.c  */
-#line 323 "parser.y"
+#line 324 "parser.y"
     { (yyval.i) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 19:
 /* Line 1787 of yacc.c  */
-#line 324 "parser.y"
+#line 325 "parser.y"
     { (yyval.i) = -(yyvsp[(2) - (2)].i); }
     break;
 
   case 20:
 /* Line 1787 of yacc.c  */
-#line 328 "parser.y"
+#line 329 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 21:
 /* Line 1787 of yacc.c  */
-#line 329 "parser.y"
+#line 330 "parser.y"
     { (yyval.r) = -(yyvsp[(2) - (2)].r); }
     break;
 
   case 22:
 /* Line 1787 of yacc.c  */
-#line 332 "parser.y"
+#line 333 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 23:
 /* Line 1787 of yacc.c  */
-#line 333 "parser.y"
+#line 334 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 24:
 /* Line 1787 of yacc.c  */
-#line 336 "parser.y"
+#line 337 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 25:
 /* Line 1787 of yacc.c  */
-#line 337 "parser.y"
+#line 338 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 26:
 /* Line 1787 of yacc.c  */
-#line 346 "parser.y"
+#line 347 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg(get((yyvsp[(2) - (2)].sel)));
@@ -2149,7 +2280,7 @@ yyreduce:
 
   case 27:
 /* Line 1787 of yacc.c  */
-#line 357 "parser.y"
+#line 358 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
@@ -2164,7 +2295,7 @@ yyreduce:
 
   case 28:
 /* Line 1787 of yacc.c  */
-#line 368 "parser.y"
+#line 369 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
@@ -2179,13 +2310,13 @@ yyreduce:
 
   case 29:
 /* Line 1787 of yacc.c  */
-#line 378 "parser.y"
+#line 379 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 30:
 /* Line 1787 of yacc.c  */
-#line 383 "parser.y"
+#line 384 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree opGuard((yyvsp[(2) - (3)].str));
@@ -2197,7 +2328,7 @@ yyreduce:
 
   case 31:
 /* Line 1787 of yacc.c  */
-#line 394 "parser.y"
+#line 395 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(2) - (2)].str));
@@ -2208,7 +2339,7 @@ yyreduce:
 
   case 32:
 /* Line 1787 of yacc.c  */
-#line 401 "parser.y"
+#line 402 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner));
@@ -2218,37 +2349,37 @@ yyreduce:
 
   case 33:
 /* Line 1787 of yacc.c  */
-#line 409 "parser.y"
+#line 410 "parser.y"
     { (yyval.str) = NULL; }
     break;
 
   case 34:
 /* Line 1787 of yacc.c  */
-#line 410 "parser.y"
+#line 411 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str);   }
     break;
 
   case 35:
 /* Line 1787 of yacc.c  */
-#line 415 "parser.y"
+#line 416 "parser.y"
     { (yyval.smt) = gmx::eStringMatchType_RegularExpression; }
     break;
 
   case 36:
 /* Line 1787 of yacc.c  */
-#line 416 "parser.y"
+#line 417 "parser.y"
     { (yyval.smt) = gmx::eStringMatchType_Wildcard; }
     break;
 
   case 37:
 /* Line 1787 of yacc.c  */
-#line 417 "parser.y"
+#line 418 "parser.y"
     { (yyval.smt) = gmx::eStringMatchType_Exact; }
     break;
 
   case 38:
 /* Line 1787 of yacc.c  */
-#line 422 "parser.y"
+#line 423 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2260,7 +2391,7 @@ yyreduce:
 
   case 39:
 /* Line 1787 of yacc.c  */
-#line 430 "parser.y"
+#line 431 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2272,7 +2403,7 @@ yyreduce:
 
   case 40:
 /* Line 1787 of yacc.c  */
-#line 438 "parser.y"
+#line 439 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (4)].str));
@@ -2284,7 +2415,7 @@ yyreduce:
 
   case 41:
 /* Line 1787 of yacc.c  */
-#line 446 "parser.y"
+#line 447 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2296,7 +2427,7 @@ yyreduce:
 
   case 42:
 /* Line 1787 of yacc.c  */
-#line 457 "parser.y"
+#line 458 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2308,7 +2439,7 @@ yyreduce:
 
   case 43:
 /* Line 1787 of yacc.c  */
-#line 472 "parser.y"
+#line 473 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2323,7 +2454,7 @@ yyreduce:
 
   case 44:
 /* Line 1787 of yacc.c  */
-#line 483 "parser.y"
+#line 484 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2338,7 +2469,7 @@ yyreduce:
 
   case 45:
 /* Line 1787 of yacc.c  */
-#line 497 "parser.y"
+#line 498 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2350,7 +2481,7 @@ yyreduce:
 
   case 46:
 /* Line 1787 of yacc.c  */
-#line 505 "parser.y"
+#line 506 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (4)].str));
@@ -2362,7 +2493,7 @@ yyreduce:
 
   case 47:
 /* Line 1787 of yacc.c  */
-#line 513 "parser.y"
+#line 514 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2374,7 +2505,7 @@ yyreduce:
 
   case 48:
 /* Line 1787 of yacc.c  */
-#line 524 "parser.y"
+#line 525 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
@@ -2384,7 +2515,7 @@ yyreduce:
 
   case 49:
 /* Line 1787 of yacc.c  */
-#line 530 "parser.y"
+#line 531 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
@@ -2394,7 +2525,7 @@ yyreduce:
 
   case 50:
 /* Line 1787 of yacc.c  */
-#line 536 "parser.y"
+#line 537 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
@@ -2404,7 +2535,7 @@ yyreduce:
 
   case 51:
 /* Line 1787 of yacc.c  */
-#line 542 "parser.y"
+#line 543 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
@@ -2414,7 +2545,7 @@ yyreduce:
 
   case 52:
 /* Line 1787 of yacc.c  */
-#line 548 "parser.y"
+#line 549 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
@@ -2424,7 +2555,7 @@ yyreduce:
 
   case 53:
 /* Line 1787 of yacc.c  */
-#line 554 "parser.y"
+#line 555 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
@@ -2434,13 +2565,13 @@ yyreduce:
 
   case 54:
 /* Line 1787 of yacc.c  */
-#line 559 "parser.y"
+#line 560 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 55:
 /* Line 1787 of yacc.c  */
-#line 567 "parser.y"
+#line 568 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2455,7 +2586,7 @@ yyreduce:
 
   case 56:
 /* Line 1787 of yacc.c  */
-#line 578 "parser.y"
+#line 579 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2467,7 +2598,7 @@ yyreduce:
 
   case 57:
 /* Line 1787 of yacc.c  */
-#line 593 "parser.y"
+#line 594 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)));
@@ -2477,13 +2608,13 @@ yyreduce:
 
   case 58:
 /* Line 1787 of yacc.c  */
-#line 601 "parser.y"
+#line 602 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 59:
 /* Line 1787 of yacc.c  */
-#line 606 "parser.y"
+#line 607 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), get((yyvsp[(2) - (2)].plist)), NULL, scanner));
@@ -2494,7 +2625,7 @@ yyreduce:
 
   case 60:
 /* Line 1787 of yacc.c  */
-#line 616 "parser.y"
+#line 617 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree keywordGuard((yyvsp[(1) - (3)].str));
@@ -2506,7 +2637,7 @@ yyreduce:
 
   case 61:
 /* Line 1787 of yacc.c  */
-#line 630 "parser.y"
+#line 631 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2516,7 +2647,7 @@ yyreduce:
 
   case 62:
 /* Line 1787 of yacc.c  */
-#line 638 "parser.y"
+#line 639 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2526,7 +2657,7 @@ yyreduce:
 
   case 63:
 /* Line 1787 of yacc.c  */
-#line 646 "parser.y"
+#line 647 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2536,19 +2667,19 @@ yyreduce:
 
   case 64:
 /* Line 1787 of yacc.c  */
-#line 659 "parser.y"
+#line 660 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (1)].plist); }
     break;
 
   case 65:
 /* Line 1787 of yacc.c  */
-#line 661 "parser.y"
+#line 662 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (2)].plist); }
     break;
 
   case 66:
 /* Line 1787 of yacc.c  */
-#line 666 "parser.y"
+#line 667 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.plist), SelectionParserParameter::createList());
@@ -2558,7 +2689,7 @@ yyreduce:
 
   case 67:
 /* Line 1787 of yacc.c  */
-#line 672 "parser.y"
+#line 673 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserParameterListPointer list(get((yyvsp[(1) - (2)].plist)));
@@ -2570,7 +2701,7 @@ yyreduce:
 
   case 68:
 /* Line 1787 of yacc.c  */
-#line 683 "parser.y"
+#line 684 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(1) - (2)].str));
@@ -2581,19 +2712,19 @@ yyreduce:
 
   case 69:
 /* Line 1787 of yacc.c  */
-#line 691 "parser.y"
+#line 692 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist);   }
     break;
 
   case 70:
 /* Line 1787 of yacc.c  */
-#line 692 "parser.y"
+#line 693 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist);   }
     break;
 
   case 71:
 /* Line 1787 of yacc.c  */
-#line 697 "parser.y"
+#line 698 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
@@ -2603,7 +2734,7 @@ yyreduce:
 
   case 72:
 /* Line 1787 of yacc.c  */
-#line 703 "parser.y"
+#line 704 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2615,7 +2746,7 @@ yyreduce:
 
   case 73:
 /* Line 1787 of yacc.c  */
-#line 711 "parser.y"
+#line 712 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2627,19 +2758,19 @@ yyreduce:
 
   case 74:
 /* Line 1787 of yacc.c  */
-#line 721 "parser.y"
+#line 722 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist); }
     break;
 
   case 75:
 /* Line 1787 of yacc.c  */
-#line 722 "parser.y"
+#line 723 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist); }
     break;
 
   case 76:
 /* Line 1787 of yacc.c  */
-#line 727 "parser.y"
+#line 728 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[(1) - (1)].val))));
@@ -2649,7 +2780,7 @@ yyreduce:
 
   case 77:
 /* Line 1787 of yacc.c  */
-#line 733 "parser.y"
+#line 734 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2661,7 +2792,7 @@ yyreduce:
 
   case 78:
 /* Line 1787 of yacc.c  */
-#line 741 "parser.y"
+#line 742 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2673,7 +2804,7 @@ yyreduce:
 
   case 79:
 /* Line 1787 of yacc.c  */
-#line 751 "parser.y"
+#line 752 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2683,7 +2814,7 @@ yyreduce:
 
   case 80:
 /* Line 1787 of yacc.c  */
-#line 757 "parser.y"
+#line 758 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2693,7 +2824,7 @@ yyreduce:
 
   case 81:
 /* Line 1787 of yacc.c  */
-#line 763 "parser.y"
+#line 764 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2703,7 +2834,7 @@ yyreduce:
 
   case 82:
 /* Line 1787 of yacc.c  */
-#line 769 "parser.y"
+#line 770 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2713,13 +2844,13 @@ yyreduce:
 
   case 83:
 /* Line 1787 of yacc.c  */
-#line 774 "parser.y"
+#line 775 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 84:
 /* Line 1787 of yacc.c  */
-#line 779 "parser.y"
+#line 780 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createInteger((yyvsp[(1) - (1)].i)));
@@ -2729,7 +2860,7 @@ yyreduce:
 
   case 85:
 /* Line 1787 of yacc.c  */
-#line 785 "parser.y"
+#line 786 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createReal((yyvsp[(1) - (1)].r)));
@@ -2739,7 +2870,7 @@ yyreduce:
 
   case 86:
 /* Line 1787 of yacc.c  */
-#line 791 "parser.y"
+#line 792 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree stringGuard((yyvsp[(1) - (1)].str));
@@ -2750,13 +2881,13 @@ yyreduce:
 
   case 87:
 /* Line 1787 of yacc.c  */
-#line 797 "parser.y"
+#line 798 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 88:
 /* Line 1787 of yacc.c  */
-#line 802 "parser.y"
+#line 803 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].i)));
@@ -2766,7 +2897,7 @@ yyreduce:
 
   case 89:
 /* Line 1787 of yacc.c  */
-#line 808 "parser.y"
+#line 809 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].r)));
@@ -2776,7 +2907,7 @@ yyreduce:
 
   case 90:
 /* Line 1787 of yacc.c  */
-#line 814 "parser.y"
+#line 815 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].r), (yyvsp[(3) - (3)].r)));
@@ -2786,7 +2917,7 @@ yyreduce:
 
 
 /* Line 1787 of yacc.c  */
-#line 2790 "parser.cpp"
+#line 2921 "parser.cpp"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2807,6 +2938,7 @@ yyreduce:
   YY_STACK_PRINT (yyss, yyssp);
 
   *++yyvsp = yyval;
+  *++yylsp = yyloc;
 
   /* Now `shift' the result of the reduction.  Determine what state
      that goes to, based on the state we popped back to and the rule
@@ -2836,7 +2968,7 @@ yyerrlab:
     {
       ++yynerrs;
 #if ! YYERROR_VERBOSE
-      yyerror (scanner, YY_("syntax error"));
+      yyerror (&yylloc, scanner, YY_("syntax error"));
 #else
 # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
                                         yyssp, yytoken)
@@ -2863,7 +2995,7 @@ yyerrlab:
                 yymsgp = yymsg;
               }
           }
-        yyerror (scanner, yymsgp);
+        yyerror (&yylloc, scanner, yymsgp);
         if (yysyntax_error_status == 2)
           goto yyexhaustedlab;
       }
@@ -2871,7 +3003,7 @@ yyerrlab:
 #endif
     }
 
-
+  yyerror_range[1] = yylloc;
 
   if (yyerrstatus == 3)
     {
@@ -2887,7 +3019,7 @@ yyerrlab:
       else
        {
          yydestruct ("Error: discarding",
-                     yytoken, &yylval, scanner);
+                     yytoken, &yylval, &yylloc, scanner);
          yychar = YYEMPTY;
        }
     }
@@ -2908,6 +3040,7 @@ yyerrorlab:
   if (/*CONSTCOND*/ 0)
      goto yyerrorlab;
 
+  yyerror_range[1] = yylsp[1-yylen];
   /* Do not reclaim the symbols of the rule which action triggered
      this YYERROR.  */
   YYPOPSTACK (yylen);
@@ -2941,9 +3074,9 @@ yyerrlab1:
       if (yyssp == yyss)
        YYABORT;
 
-
+      yyerror_range[1] = *yylsp;
       yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp, scanner);
+                 yystos[yystate], yyvsp, yylsp, scanner);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -2953,6 +3086,11 @@ yyerrlab1:
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
 
+  yyerror_range[2] = yylloc;
+  /* Using YYLLOC is tempting, but would change the location of
+     the lookahead.  YYLOC is available though.  */
+  YYLLOC_DEFAULT (yyloc, yyerror_range, 2);
+  *++yylsp = yyloc;
 
   /* Shift the error token.  */
   YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
@@ -2980,7 +3118,7 @@ yyabortlab:
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 yyexhaustedlab:
-  yyerror (scanner, YY_("memory exhausted"));
+  yyerror (&yylloc, scanner, YY_("memory exhausted"));
   yyresult = 2;
   /* Fall through.  */
 #endif
@@ -2992,7 +3130,7 @@ yyreturn:
          user semantic actions for why this is necessary.  */
       yytoken = YYTRANSLATE (yychar);
       yydestruct ("Cleanup: discarding lookahead",
-                  yytoken, &yylval, scanner);
+                  yytoken, &yylval, &yylloc, scanner);
     }
   /* Do not reclaim the symbols of the rule which action triggered
      this YYABORT or YYACCEPT.  */
@@ -3001,7 +3139,7 @@ yyreturn:
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp, scanner);
+                 yystos[*yyssp], yyvsp, yylsp, scanner);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
index f3f96fdfd2e741927fc72180033e1b9bfbbe7af1..3a70dcf359f27299ebcad975b04262bca8e98b5c 100644 (file)
@@ -84,9 +84,11 @@ extern int _gmx_sel_yydebug;
 #include "parsetree.h"
 #include "selelem.h"
 
+#define YYLTYPE ::gmx::SelectionLocation
+
 
 /* Line 2053 of yacc.c  */
-#line 90 "parser.h"
+#line 92 "parser.h"
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -133,7 +135,7 @@ extern int _gmx_sel_yydebug;
 typedef union YYSTYPE
 {
 /* Line 2053 of yacc.c  */
-#line 81 "parser.y"
+#line 83 "parser.y"
 
     int                         i;
     real                        r;
@@ -150,13 +152,26 @@ typedef union YYSTYPE
 
 
 /* Line 2053 of yacc.c  */
-#line 154 "parser.h"
+#line 156 "parser.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
 
 #ifndef YYPUSH_MORE_DEFINED
 # define YYPUSH_MORE_DEFINED
@@ -166,7 +181,7 @@ enum { YYPUSH_MORE = 4 };
 typedef struct _gmx_sel_yypstate _gmx_sel_yypstate;
 
 #if defined __STDC__ || defined __cplusplus
-int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, void *scanner);
+int _gmx_sel_yypush_parse (_gmx_sel_yypstate *ps, int pushed_char, YYSTYPE const *pushed_val, YYLTYPE *pushed_loc, void *scanner);
 #else
 int _gmx_sel_yypush_parse ();
 #endif
index 940535e2715ed78b1005f5092cda486bb137a0cc..de16101d2ba39ccbf28d0b1fb6db1ace6bf69c18 100644 (file)
@@ -1,6 +1,15 @@
---- parser.cpp 2014-08-11 22:24:31.000000000 +0200
-+++ parser.cpp 2014-08-11 22:24:40.000000000 +0200
-@@ -963,7 +963,7 @@
+--- parser.cpp 2014-11-03 06:56:28.000000000 +0200
++++ parser.cpp 2014-11-03 06:57:35.000000000 +0200
+@@ -470,7 +470,7 @@
+ #if (! defined yyoverflow \
+-     && (! defined __cplusplus \
++     && (! defined __cplusplus || defined GMX_YYFORCE_C_STACK_EXTENSION \
+        || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+            && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+@@ -1076,7 +1076,7 @@
      void *scanner;
  #endif
  {
index 384c6fdaa2eec21e17440cceca599c6e69aaf753..d28686f09de13afafe9138ee8b588252e630dfb0 100644 (file)
@@ -76,6 +76,8 @@ using gmx::SelectionTreeElementPointer;
 %code requires{
 #include "parsetree.h"
 #include "selelem.h"
+
+#define YYLTYPE ::gmx::SelectionLocation
 }
 
 %union{
@@ -185,6 +187,7 @@ using gmx::SelectionTreeElementPointer;
 %debug
 %pure-parser
 %define api.push-pull push
+%locations
 
 %name-prefix="_gmx_sel_yy"
 %parse-param { void *scanner }
@@ -196,7 +199,7 @@ commands:    /* empty */
              {
                  BEGIN_ACTION;
                  set_empty($$);
-                 END_ACTION;
+                 END_ACTION_TOPLEVEL;
              }
            | commands command
              {
@@ -204,7 +207,7 @@ commands:    /* empty */
                  set($$, _gmx_sel_append_selection(get($2), get($1), scanner));
                  if (_gmx_sel_parser_should_finish(scanner))
                      YYACCEPT;
-                 END_ACTION;
+                 END_ACTION_TOPLEVEL;
              }
 ;
 
@@ -213,20 +216,18 @@ command:     cmd_plain CMD_SEP  { $$ = $1; }
            | error CMD_SEP
              {
                  BEGIN_ACTION;
-                 _gmx_selparser_error(scanner, "invalid selection '%s'",
-                                      _gmx_sel_lexer_pselstr(scanner));
                  _gmx_sel_lexer_clear_method_stack(scanner);
-                 if (_gmx_sel_is_lexer_interactive(scanner))
+                 if (_gmx_selparser_handle_error(scanner))
                  {
-                     _gmx_sel_lexer_clear_pselstr(scanner);
                      yyerrok;
                  }
                  else
                  {
                      YYABORT;
                  }
+                 _gmx_sel_lexer_clear_pselstr(scanner);
                  set_empty($$);
-                 END_ACTION;
+                 END_ACTION_TOPLEVEL;
              }
 ;
 
index b938adfa6c1207470bebc785764793572a8988d8..f00413346f22174394ca83a97e28b0645ac3aa38 100644 (file)
 
 #include <exception>
 
+#include <boost/exception_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
 
 #include "parsetree.h"
 #include "scanner.h"
 
 //! Error handler needed by Bison.
 static void
-yyerror(yyscan_t scanner, char const *s)
+yyerror(YYLTYPE *location, yyscan_t scanner, char const *s)
 {
-    _gmx_selparser_error(scanner, "%s", s);
+    try
+    {
+        std::string            context(_gmx_sel_lexer_get_text(scanner, *location));
+        gmx::InvalidInputError ex(s);
+        // TODO: Examine how to show better context information.
+        if (!context.empty())
+        {
+            context = gmx::formatString("Near '%s'", context.c_str());
+            ex.prependContext(context);
+        }
+        _gmx_sel_lexer_set_exception(scanner, boost::copy_exception(ex));
+    }
+    catch (const std::exception &)
+    {
+        _gmx_sel_lexer_set_exception(scanner, boost::current_exception());
+    }
 }
 
+//! Logic for computing the location of the output of Bison reduction.
+#define YYLLOC_DEFAULT(Current, Rhs, N)                          \
+    do {                                                         \
+        if (N != 0)                                              \
+        {                                                        \
+            (Current).startIndex = YYRHSLOC(Rhs, 1).startIndex;  \
+            (Current).endIndex   = YYRHSLOC(Rhs, N).endIndex;    \
+        }                                                        \
+        else                                                     \
+        {                                                        \
+            (Current).startIndex = (Current).endIndex =          \
+                    YYRHSLOC(Rhs, 0).endIndex;                   \
+        }                                                        \
+        _gmx_sel_lexer_set_current_location(scanner, (Current)); \
+    } while (0)
+
+/*! \brief
+ * Custom macro to influence Bison behavior.
+ *
+ * This macro added to parser.cpp through our patch to force Bison to
+ * use C-style logic for stack reallocation even though we have provided
+ * YYLTYPE and are compiling the code in C++ (our YYLTYPE can safely be copied
+ * this way).
+ * An alternative would be to provide the whole reallocation logic through an
+ * undocumented yyoverflow() macro, but that is probably also more trouble than
+ * it is worth.
+ */
+#define GMX_YYFORCE_C_STACK_EXTENSION 1
+
 /*! \name Exception handling macros for actions
  *
  * These macros should be used at the beginning and end of each semantic action
@@ -81,14 +128,26 @@ yyerror(yyscan_t scanner, char const *s)
 #define BEGIN_ACTION \
     try {
 //! Finishes an action that may throw exceptions.
-#define END_ACTION \
-    } \
-    catch (const std::exception &ex) \
-    { \
-        if (_gmx_selparser_handle_exception(scanner, ex)) { \
-            YYERROR; } \
-        else{ \
-            YYABORT; } \
+#define END_ACTION                                              \
+    }                                                           \
+    catch (std::exception &ex)                                  \
+    {                                                           \
+        if (_gmx_selparser_handle_exception(scanner, &ex))      \
+        {                                                       \
+            YYERROR;                                            \
+        }                                                       \
+        else                                                    \
+        {                                                       \
+            YYABORT;                                            \
+        }                                                       \
+    }
+//! Finishes an action that may throw exceptions and does not support resuming.
+#define END_ACTION_TOPLEVEL                                     \
+    }                                                           \
+    catch (const std::exception &)                              \
+    {                                                           \
+        _gmx_sel_lexer_set_exception(scanner, boost::current_exception()); \
+        YYABORT;                                                \
     }
 //!\}
 
index 6bb7bd4a9b6fb87429f0b29c59af809e44723b15..8b13207cd6a8bb6b398c60547396cd1ab05893a4 100644 (file)
@@ -255,6 +255,25 @@ using gmx::SelectionParserValue;
 using gmx::SelectionTreeElement;
 using gmx::SelectionTreeElementPointer;
 
+namespace
+{
+
+/*! \brief
+ * Formats context string for errors.
+ *
+ * The returned string is used as the context for errors reported during
+ * parsing.
+ */
+std::string
+formatCurrentErrorContext(yyscan_t scanner)
+{
+    return gmx::formatString(
+            "While parsing '%s'",
+            _gmx_sel_lexer_get_current_text(scanner).c_str());
+}
+
+} // namespace
+
 void
 _gmx_selparser_error(yyscan_t scanner, const char *fmt, ...)
 {
@@ -269,22 +288,58 @@ _gmx_selparser_error(yyscan_t scanner, const char *fmt, ...)
 }
 
 bool
-_gmx_selparser_handle_exception(yyscan_t scanner, const std::exception &ex)
+_gmx_selparser_handle_exception(yyscan_t scanner, std::exception *ex)
+{
+    try
+    {
+        bool                   canContinue = false;
+        gmx::GromacsException *gromacsException
+            = dynamic_cast<gmx::GromacsException *>(ex);
+        if (gromacsException != NULL)
+        {
+            gromacsException->prependContext(formatCurrentErrorContext(scanner));
+            canContinue = (dynamic_cast<gmx::UserInputError *>(ex) != NULL);
+        }
+        _gmx_sel_lexer_set_exception(scanner, boost::current_exception());
+        return canContinue;
+    }
+    catch (const std::exception &)
+    {
+        _gmx_sel_lexer_set_exception(scanner, boost::current_exception());
+        return false;
+    }
+}
+
+bool
+_gmx_selparser_handle_error(yyscan_t scanner)
 {
-    if (dynamic_cast<const gmx::UserInputError *>(&ex) != NULL)
+    std::string context(gmx::formatString("In selection '%s'",
+                                          _gmx_sel_lexer_pselstr(scanner)));
+    // The only way to prepend context to the exception is to rethrow it.
+    try
+    {
+        _gmx_sel_lexer_rethrow_exception_if_occurred(scanner);
+    }
+    catch (gmx::UserInputError &ex)
     {
-        // TODO: Consider whether also the non-interactive parser should
-        // postpone the exception such that the whole selection can be added as
-        // context.
+        ex.prependContext(context);
         if (_gmx_sel_is_lexer_interactive(scanner))
         {
-            // TODO: Handle exceptions that printing the message may produce.
             gmx::formatExceptionMessageToFile(stderr, ex);
             return true;
         }
+        throw;
     }
-    _gmx_sel_lexer_set_exception(scanner, boost::current_exception());
-    return false;
+    catch (gmx::GromacsException &ex)
+    {
+        ex.prependContext(context);
+        throw;
+    }
+    // Do legacy processing for non-exception cases.
+    // This is only reached if there was no active exception.
+    _gmx_selparser_error(scanner, "Invalid selection '%s'",
+                         _gmx_sel_lexer_pselstr(scanner));
+    return _gmx_sel_is_lexer_interactive(scanner);
 }
 
 namespace gmx
@@ -604,7 +659,7 @@ _gmx_sel_init_comparison(const gmx::SelectionTreeElementPointer &left,
                          const char *cmpop, yyscan_t scanner)
 {
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
-    gmx::MessageStringContext    context(errors, "In comparison initialization");
+    gmx::MessageStringContext    context(errors, formatCurrentErrorContext(scanner));
 
     SelectionTreeElementPointer  sel(new SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(sel, &sm_compare, scanner);
@@ -653,9 +708,7 @@ init_keyword_internal(gmx_ana_selmethod_t *method,
     gmx_ana_selcollection_t     *sc = _gmx_sel_lexer_selcollection(scanner);
 
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
-    char  buf[128];
-    sprintf(buf, "In keyword '%s'", method->name);
-    gmx::MessageStringContext  context(errors, buf);
+    gmx::MessageStringContext    context(errors, formatCurrentErrorContext(scanner));
 
     if (method->nparams > 0)
     {
@@ -762,9 +815,7 @@ _gmx_sel_init_keyword_of(gmx_ana_selmethod_t                    *method,
                          const char *rpost, yyscan_t scanner)
 {
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
-    char  buf[128];
-    sprintf(buf, "In '%s of'", method->name);
-    gmx::MessageStringContext    context(errors, buf);
+    gmx::MessageStringContext    context(errors, formatCurrentErrorContext(scanner));
 
     GMX_UNUSED_VALUE(rpost);
     return _gmx_sel_init_keyword_evaluator(method, group, scanner);
@@ -794,9 +845,7 @@ _gmx_sel_init_method(gmx_ana_selmethod_t                      *method,
     int                          rc;
 
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
-    char  buf[128];
-    sprintf(buf, "In keyword '%s'", method->name);
-    gmx::MessageStringContext  context(errors, buf);
+    gmx::MessageStringContext    context(errors, formatCurrentErrorContext(scanner));
 
     _gmx_sel_finish_method(scanner);
     /* The "same" keyword needs some custom massaging of the parameters. */
@@ -835,9 +884,7 @@ _gmx_sel_init_modifier(gmx_ana_selmethod_t                      *method,
                        yyscan_t                                  scanner)
 {
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
-    char  buf[128];
-    sprintf(buf, "In keyword '%s'", method->name);
-    gmx::MessageStringContext  context(errors, buf);
+    gmx::MessageStringContext    context(errors, formatCurrentErrorContext(scanner));
 
     _gmx_sel_finish_method(scanner);
     SelectionTreeElementPointer modifier(new SelectionTreeElement(SEL_MODIFIER));
@@ -883,11 +930,9 @@ _gmx_sel_init_position(const gmx::SelectionTreeElementPointer &expr,
                        const char *type, yyscan_t scanner)
 {
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
-    char  buf[128];
-    sprintf(buf, "In position evaluation");
-    gmx::MessageStringContext   context(errors, buf);
+    gmx::MessageStringContext    context(errors, formatCurrentErrorContext(scanner));
 
-    SelectionTreeElementPointer root(new SelectionTreeElement(SEL_EXPRESSION));
+    SelectionTreeElementPointer  root(new SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(root, &sm_keyword_pos, scanner);
     _gmx_selelem_set_kwpos_type(root.get(), type);
     /* Create the parameters for the parameter parser. */
index d84d68cea82053aef70b3a4b9a15a98c1db166ff..00972c372ba3c0647aa25013524bef3e85770349 100644 (file)
@@ -377,9 +377,48 @@ class SelectionParserParameter
 /** Error reporting function for the selection parser. */
 void
 _gmx_selparser_error(void *scanner, const char *fmt, ...);
-/** Handle exceptions caught within the Bison code. */
+/*! \brief
+ * Handles exceptions caught within the Bison code.
+ *
+ * \retval `true`  if the parser should attempt error recovery.
+ * \retval `false` if the parser should immediately abort.
+ *
+ * This function is called whenever an exception is caught within Bison
+ * actions.  Since exceptions cannot propagate through Bison code, the
+ * exception is saved (potentially with some extra context information) so that
+ * the caller of the parser can rethrow the exception.
+ *
+ * If it is possible to recover from the exception, then the function returns
+ * `true`, and Bison enters error recovery state.  At the end of the recovery,
+ * _gmx_selparser_handle_error() is called.
+ * If this function returns false, then Bison immediately aborts the parsing
+ * so that the caller can rethrow the exception.
+ */
+bool
+_gmx_selparser_handle_exception(void *scanner, std::exception *ex);
+/*! \brief
+ * Handles errors in the selection parser.
+ *
+ * \returns `true` if parsing can continue with the next selection.
+ * \throws  std::bad_alloc if out of memory during the error processing.
+ * \throws  unspecified    Can throw the stored exception if recovery from that
+ *     exception is not possible.
+ *
+ * This function is called during error recovery, after Bison has discarded all
+ * the symbols for the erroneous selection.
+ * At this point, the full selection that caused the error is known, and can be
+ * added to the error context.
+ *
+ * For an interactive parser, this function returns `true` to let the parsing
+ * continue with the next selection, or to let the user enter the next
+ * selection, if it was possible to recover from the exception.
+ * For other cases, this will either rethrow the original exception with added
+ * context, or return `false` after adding the context to the error reporter.
+ * Any exceptions thrown from this method are again caught by Bison and result
+ * in termination of the parsing; the caller can then rethrow them.
+ */
 bool
-_gmx_selparser_handle_exception(void *scanner, const std::exception &ex);
+_gmx_selparser_handle_error(void *scanner);
 
 /** Propagates the flags for selection elements. */
 void
index 681a52194cd639017fe85f87e661a59cd60a26c8..f4c9354ffe0cfdee7d03896951faa3647c450b53 100644 (file)
@@ -550,7 +550,7 @@ static yyconst flex_int16_t yy_chk[151] =
 
 // This macro makes the actions a bit shorter, since nearly every action needs
 // this call.
-#define ADD_TOKEN _gmx_sel_lexer_add_token(yytext, yyleng, state)
+#define ADD_TOKEN _gmx_sel_lexer_add_token(yylloc, yytext, yyleng, state)
 
 // Set YY_BREAK to an empty value to avoid warnings (for the PGI compiler)
 // when we have return statements followed by break. Instead, we add breaks
@@ -795,7 +795,7 @@ YY_DECL
     gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(yyscanner);
     int              retval;
     /* Return a token if one is pending */
-    retval = _gmx_sel_lexer_process_pending(yylval, state);
+    retval = _gmx_sel_lexer_process_pending(yylval, yylloc, state);
     if (retval != 0)
     {
         return retval;
@@ -925,7 +925,7 @@ case 5:
 /* rule 5 can match eol */
 YY_RULE_SETUP
 #line 136 "scanner.l"
-{ _gmx_sel_lexer_add_token(" ", 1, state); break; }
+{ _gmx_sel_lexer_add_token(yylloc, " ", 1, state); break; }
        YY_BREAK
 case 6:
 /* rule 6 can match eol */
@@ -940,7 +940,7 @@ YY_RULE_SETUP
                     }
                     else
                     {
-                        _gmx_sel_lexer_add_token(" ", 1, state);
+                        _gmx_sel_lexer_add_token(yylloc, " ", 1, state);
                     }
                     break;
                 }
@@ -1010,13 +1010,13 @@ YY_RULE_SETUP
 case 17:
 YY_RULE_SETUP
 #line 167 "scanner.l"
-{ return _gmx_sel_lexer_process_identifier(yylval, yytext, yyleng, state); }
+{ return _gmx_sel_lexer_process_identifier(yylval, yylloc, yytext, yyleng, state); }
        YY_BREAK
 case 18:
 /* rule 18 can match eol */
 YY_RULE_SETUP
 #line 169 "scanner.l"
-{ _gmx_sel_lexer_add_token(" ", 1, state); break; }
+{ _gmx_sel_lexer_add_token(yylloc, " ", 1, state); break; }
        YY_BREAK
 case 19:
 YY_RULE_SETUP
index 14f941a36da068a72099eb55fd8d3bfa6fffc33b..a058062e21c2aa39db174e69cf85f927bb275099 100644 (file)
@@ -45,6 +45,8 @@
 #ifndef SELECTION_SCANNER_H
 #define SELECTION_SCANNER_H
 
+#include <string>
+
 #include <boost/exception_ptr.hpp>
 
 #include "parser.h"
@@ -106,6 +108,26 @@ _gmx_sel_lexer_exp_selcount(yyscan_t scanner);
 /** Returns a pretty string of the current selection.  */
 const char *
 _gmx_sel_lexer_pselstr(yyscan_t scanner);
+/*! \brief
+ * Sets the current parser context location.
+ */
+void
+_gmx_sel_lexer_set_current_location(yyscan_t                      scanner,
+                                    const gmx::SelectionLocation &location);
+/*! \brief
+ * Returns the selection text for the current parser context.
+ *
+ * This returns the selection text that corresponds to the position set last
+ * with _gmx_sel_lexer_set_current_location().
+ */
+std::string
+_gmx_sel_lexer_get_current_text(yyscan_t scanner);
+/*! \brief
+ * Returns the selection text at the given location.
+ */
+std::string
+_gmx_sel_lexer_get_text(yyscan_t                      scanner,
+                        const gmx::SelectionLocation &location);
 /** Clears the current selection string.  */
 void
 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner);
@@ -123,7 +145,7 @@ void
 _gmx_sel_set_lex_input_str(yyscan_t scanner, const char *str);
 
 /** The scanning function generated by Flex. */
-#define YY_DECL int _gmx_sel_yylex(YYSTYPE *yylval, yyscan_t yyscanner)
+#define YY_DECL int _gmx_sel_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, yyscan_t yyscanner)
 YY_DECL;
 
 #endif
index bb4a17c208847bece72013e088ecac2cee048c3f..f9a117d96ceeac982e363660fae51310437753c4 100644 (file)
@@ -65,7 +65,7 @@
 
 // This macro makes the actions a bit shorter, since nearly every action needs
 // this call.
-#define ADD_TOKEN _gmx_sel_lexer_add_token(yytext, yyleng, state)
+#define ADD_TOKEN _gmx_sel_lexer_add_token(yylloc, yytext, yyleng, state)
 
 // Set YY_BREAK to an empty value to avoid warnings (for the PGI compiler)
 // when we have return statements followed by break. Instead, we add breaks
@@ -101,7 +101,7 @@ COMMENT    (#.*)
     gmx_sel_lexer_t *state = yyget_extra(yyscanner);
     int              retval;
     /* Return a token if one is pending */
-    retval = _gmx_sel_lexer_process_pending(yylval, state);
+    retval = _gmx_sel_lexer_process_pending(yylval, yylloc, state);
     if (retval != 0)
     {
         return retval;
@@ -133,7 +133,7 @@ COMMENT    (#.*)
 {REAL}          { yylval->r   = strtod(yytext, NULL);        ADD_TOKEN; return TOK_REAL; }
 {STRING}        { yylval->str = gmx_strndup(yytext+1, yyleng-2); ADD_TOKEN; return STR;  }
 
-\\\n            { _gmx_sel_lexer_add_token(" ", 1, state); break; }
+\\\n            { _gmx_sel_lexer_add_token(yylloc, " ", 1, state); break; }
 ";"|\n          {
                     if (yytext[0] == ';' || state->bInteractive)
                     {
@@ -143,7 +143,7 @@ COMMENT    (#.*)
                     }
                     else
                     {
-                        _gmx_sel_lexer_add_token(" ", 1, state);
+                        _gmx_sel_lexer_add_token(yylloc, " ", 1, state);
                     }
                     break;
                 }
@@ -164,8 +164,8 @@ xor             { ADD_TOKEN; return XOR; }
 not|"!"         { ADD_TOKEN; return NOT; }
 {CMPOP}         { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return CMP_OP; }
 
-{IDENTIFIER}    { return _gmx_sel_lexer_process_identifier(yylval, yytext, yyleng, state); }
+{IDENTIFIER}    { return _gmx_sel_lexer_process_identifier(yylval, yylloc, yytext, yyleng, state); }
 
-[[:space:]]+    { _gmx_sel_lexer_add_token(" ", 1, state); break; }
+[[:space:]]+    { _gmx_sel_lexer_add_token(yylloc, " ", 1, state); break; }
 [_[:alnum:]]+   { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return STR; }
 .               { ADD_TOKEN; return yytext[0]; }
index 446bc99e4bd70578cfeea16898d0d0eaecf4e74a..dfd91b1c59ae622b8b9890391eec41eb8303a03f 100644 (file)
@@ -113,16 +113,20 @@ init_param_token(YYSTYPE *yylval, gmx_ana_selparam_t *param, bool bBoolNo)
  * Processes a selection method token.
  */
 static int
-init_method_token(YYSTYPE *yylval, gmx_ana_selmethod_t *method, bool bPosMod,
-                  gmx_sel_lexer_t *state)
+init_method_token(YYSTYPE *yylval, YYLTYPE *yylloc,
+                  const gmx::SelectionParserSymbol *symbol,
+                  bool bPosMod, gmx_sel_lexer_t *state)
 {
+    gmx_ana_selmethod_t *method = symbol->methodValue();
     /* If the previous token was not KEYWORD_POS, return EMPTY_POSMOD
      * before the actual method to work around a limitation in Bison. */
     if (!bPosMod && method->type != POS_VALUE)
     {
-        state->nextmethod = method;
+        state->nextMethodSymbol = symbol;
+        _gmx_sel_lexer_add_token(yylloc, NULL, 0, state);
         return EMPTY_POSMOD;
     }
+    _gmx_sel_lexer_add_token(yylloc, symbol->name().c_str(), -1, state);
     yylval->meth = method;
     if (!(method->flags & SMETH_MODIFIER) && method->nparams == 0)
     {
@@ -184,7 +188,8 @@ init_method_token(YYSTYPE *yylval, gmx_ana_selmethod_t *method, bool bPosMod,
 }
 
 int
-_gmx_sel_lexer_process_pending(YYSTYPE *yylval, gmx_sel_lexer_t *state)
+_gmx_sel_lexer_process_pending(YYSTYPE *yylval, YYLTYPE *yylloc,
+                               gmx_sel_lexer_t *state)
 {
     if (state->nextparam)
     {
@@ -194,29 +199,30 @@ _gmx_sel_lexer_process_pending(YYSTYPE *yylval, gmx_sel_lexer_t *state)
         if (state->neom > 0)
         {
             --state->neom;
+            _gmx_sel_lexer_add_token(yylloc, NULL, 0, state);
             return END_OF_METHOD;
         }
         state->nextparam = NULL;
         state->bBoolNo   = false;
-        _gmx_sel_lexer_add_token(param->name, -1, state);
+        _gmx_sel_lexer_add_token(yylloc, param->name, -1, state);
         return init_param_token(yylval, param, bBoolNo);
     }
     if (state->prev_pos_kw > 0)
     {
         --state->prev_pos_kw;
     }
-    if (state->nextmethod)
+    if (state->nextMethodSymbol)
     {
-        gmx_ana_selmethod_t *method = state->nextmethod;
-
-        state->nextmethod = NULL;
-        return init_method_token(yylval, method, true, state);
+        const gmx::SelectionParserSymbol *symbol = state->nextMethodSymbol;
+        state->nextMethodSymbol = NULL;
+        return init_method_token(yylval, yylloc, symbol, true, state);
     }
     return 0;
 }
 
 int
-_gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
+_gmx_sel_lexer_process_identifier(YYSTYPE *yylval, YYLTYPE *yylloc,
+                                  char *yytext, size_t yyleng,
                                   gmx_sel_lexer_t *state)
 {
     /* Check if the identifier matches with a parameter name */
@@ -269,7 +275,7 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
                 state->bBoolNo   = bBoolNo;
                 return END_OF_METHOD;
             }
-            _gmx_sel_lexer_add_token(param->name, -1, state);
+            _gmx_sel_lexer_add_token(yylloc, param->name, -1, state);
             return init_param_token(yylval, param, bBoolNo);
         }
     }
@@ -281,11 +287,16 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
     if (!symbol)
     {
         yylval->str = gmx_strndup(yytext, yyleng);
-        _gmx_sel_lexer_add_token(yytext, yyleng, state);
+        _gmx_sel_lexer_add_token(yylloc, yytext, yyleng, state);
         return IDENTIFIER;
     }
-    _gmx_sel_lexer_add_token(symbol->name().c_str(), -1, state);
     gmx::SelectionParserSymbol::SymbolType symtype = symbol->type();
+    /* For method symbols, we need some extra processing. */
+    if (symtype == gmx::SelectionParserSymbol::MethodSymbol)
+    {
+        return init_method_token(yylval, yylloc, symbol, state->prev_pos_kw > 0, state);
+    }
+    _gmx_sel_lexer_add_token(yylloc, symbol->name().c_str(), -1, state);
     /* Reserved symbols should have been caught earlier */
     if (symtype == gmx::SelectionParserSymbol::ReservedSymbol)
     {
@@ -328,12 +339,6 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
         }
         /* This position should not be reached. */
     }
-    /* For method symbols, return the correct type */
-    if (symtype == gmx::SelectionParserSymbol::MethodSymbol)
-    {
-        gmx_ana_selmethod_t *method = symbol->methodValue();
-        return init_method_token(yylval, method, state->prev_pos_kw > 0, state);
-    }
     /* For position symbols, we need to return KEYWORD_POS, but we also need
      * some additional handling. */
     if (symtype == gmx::SelectionParserSymbol::PositionSymbol)
@@ -348,8 +353,10 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
 }
 
 void
-_gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state)
+_gmx_sel_lexer_add_token(YYLTYPE *yylloc, const char *str, int len,
+                         gmx_sel_lexer_t *state)
 {
+    yylloc->startIndex = yylloc->endIndex = state->pslen;
     /* Do nothing if the string is empty, or if it is a space and there is
      * no other text yet, or if there already is a space. */
     if (!str || len == 0 || strlen(str) == 0
@@ -373,6 +380,7 @@ _gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state)
     strncpy(state->pselstr + state->pslen, str, len);
     state->pslen                += len;
     state->pselstr[state->pslen] = 0;
+    yylloc->endIndex             = state->pslen;
 }
 
 void
@@ -398,22 +406,24 @@ _gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
     state->bInteractive = bInteractive;
 
     snew(state->pselstr, STRSTORE_ALLOCSTEP);
-    state->pselstr[0]   = 0;
-    state->pslen        = 0;
-    state->nalloc_psel  = STRSTORE_ALLOCSTEP;
+    state->pselstr[0]                 = 0;
+    state->pslen                      = 0;
+    state->nalloc_psel                = STRSTORE_ALLOCSTEP;
+    state->currentLocation.startIndex = 0;
+    state->currentLocation.endIndex   = 0;
 
     snew(state->mstack, 20);
-    state->mstack_alloc = 20;
-    state->msp          = -1;
-    state->neom         = 0;
-    state->nextparam    = NULL;
-    state->nextmethod   = NULL;
-    state->prev_pos_kw  = 0;
-    state->bBoolNo      = false;
-    state->bMatchOf     = false;
-    state->bMatchBool   = false;
-    state->bCmdStart    = true;
-    state->bBuffer      = false;
+    state->mstack_alloc     = 20;
+    state->msp              = -1;
+    state->neom             = 0;
+    state->nextparam        = NULL;
+    state->nextMethodSymbol = NULL;
+    state->prev_pos_kw      = 0;
+    state->bBoolNo          = false;
+    state->bMatchOf         = false;
+    state->bMatchBool       = false;
+    state->bCmdStart        = true;
+    state->bBuffer          = false;
 
     _gmx_sel_yyset_extra(state, *scannerp);
 }
@@ -511,6 +521,35 @@ _gmx_sel_lexer_pselstr(yyscan_t scanner)
     return state->pselstr;
 }
 
+void
+_gmx_sel_lexer_set_current_location(yyscan_t                      scanner,
+                                    const gmx::SelectionLocation &location)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    state->currentLocation = location;
+}
+
+std::string
+_gmx_sel_lexer_get_current_text(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return _gmx_sel_lexer_get_text(scanner, state->currentLocation);
+}
+
+std::string
+_gmx_sel_lexer_get_text(yyscan_t                      scanner,
+                        const gmx::SelectionLocation &location)
+{
+    gmx_sel_lexer_t *state      = _gmx_sel_yyget_extra(scanner);
+    const int        startIndex = location.startIndex;
+    const int        endIndex   = location.endIndex;
+    if (startIndex >= endIndex)
+    {
+        return std::string();
+    }
+    return std::string(&state->pselstr[startIndex], endIndex - startIndex);
+}
+
 void
 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner)
 {
index 1c02c499ec24670d0a48206575aa1fe0f72f187d..9a407cc9a73ba22d7b6cd6ec551e6ceb41114d02 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -48,6 +48,7 @@
 namespace gmx
 {
 class MessageStringCollector;
+class SelectionParserSymbol;
 }
 
 /* These need to be defined before including scanner_flex.h, because it
@@ -92,6 +93,13 @@ typedef struct gmx_sel_lexer_t
     int                              pslen;
     //! Number of bytes allocated for \a pselstr.
     int                              nalloc_psel;
+    /*! \brief
+     * Position of the result of the current Bison action.
+     *
+     * This identifies the part of \a pselstr that corresponds to the
+     * subselection that is currently being reduced by Bison.
+     */
+    gmx::SelectionLocation           currentLocation;
 
     //! Stack of methods in which parameters should be looked up.
     struct gmx_ana_selmethod_t     **mstack;
@@ -111,9 +119,9 @@ typedef struct gmx_sel_lexer_t
      *
      * Only used when \p nextparam is NULL.
      */
-    struct gmx_ana_selmethod_t      *nextmethod;
+    const gmx::SelectionParserSymbol *nextMethodSymbol;
     //! Used to track whether the previous token was a position modifier.
-    int                              prev_pos_kw;
+    int                               prev_pos_kw;
 
     //! Whether the 'of' keyword is acceptable as the next token.
     bool                             bMatchOf;
@@ -133,13 +141,13 @@ typedef struct gmx_sel_lexer_t
  * we cannot have them here as parameter names... */
 /** Internal function for cases where several tokens need to be returned. */
 int
-_gmx_sel_lexer_process_pending(YYSTYPE *, gmx_sel_lexer_t *state);
+_gmx_sel_lexer_process_pending(YYSTYPE *, YYLTYPE *, gmx_sel_lexer_t *state);
 /** Internal function that processes identifier tokens. */
 int
-    _gmx_sel_lexer_process_identifier(YYSTYPE *, char *, size_t,
+    _gmx_sel_lexer_process_identifier(YYSTYPE *, YYLTYPE *, char *, size_t,
                                       gmx_sel_lexer_t *state);
 /** Internal function to add a token to the pretty-printed selection text. */
 void
-_gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state);
+_gmx_sel_lexer_add_token(YYLTYPE *, const char *str, int len, gmx_sel_lexer_t *state);
 
 #endif
index f4bfd210a0663e69171982c1769970f3d5a9dc5f..e465ed69a0235136992b32620a25a1a0168bb559 100644 (file)
@@ -190,7 +190,8 @@ int runParserLoop(yyscan_t scanner, _gmx_sel_yypstate *parserState,
     do
     {
         YYSTYPE value;
-        int     token = _gmx_sel_yylex(&value, scanner);
+        YYLTYPE location;
+        int     token = _gmx_sel_yylex(&value, &location, scanner);
         if (bInteractive)
         {
             if (token == 0)
@@ -206,7 +207,7 @@ int runParserLoop(yyscan_t scanner, _gmx_sel_yypstate *parserState,
             }
             prevToken = token;
         }
-        status = _gmx_sel_yypush_parse(parserState, token, &value, scanner);
+        status = _gmx_sel_yypush_parse(parserState, token, &value, &location, scanner);
     }
     while (status == YYPUSH_MORE);
     _gmx_sel_lexer_rethrow_exception_if_occurred(scanner);
@@ -387,8 +388,11 @@ SelectionList runParser(yyscan_t scanner, bool bStdIn, int maxnr,
                     errors.clear();
                 }
             }
-            status = _gmx_sel_yypush_parse(parserState.get(), 0, NULL,
-                                           scanner);
+            {
+                YYLTYPE location;
+                status = _gmx_sel_yypush_parse(parserState.get(), 0, NULL,
+                                               &location, scanner);
+            }
             _gmx_sel_lexer_rethrow_exception_if_occurred(scanner);
 early_termination:
             bOk = (status == 0);
index 5fa419cab9abdd9aabc78b2401b853d253a0fa35..08f25e1764e4b572e28950cb9007221131f3d760 100644 (file)
@@ -239,12 +239,33 @@ namespace gmx
 
 class ExceptionInitializer;
 
+//! \cond internal
 /*! \brief
  * Function pointer for evaluating a gmx::SelectionTreeElement.
  */
 typedef void (*sel_evalfunc)(struct gmx_sel_evaluate_t         *data,
                              const SelectionTreeElementPointer &sel,
                              gmx_ana_index_t                   *g);
+//! \endcond
+
+/*! \internal
+ * \brief
+ * Stores the location of a selection element in the selection text.
+ *
+ * The location is stored as a range in the pretty-printed selection text
+ * (where whitespace has been sanitized), and can be used to extract that text
+ * for error messages and other diagnostic purposes.
+ * During parsing, the extraction is done with _gmx_sel_lexer_get_text().
+ *
+ * This needs to be a plain C struct for Bison to properly deal with it.
+ */
+struct SelectionLocation
+{
+    //! Start index of the string where this element has been parsed from.
+    int  startIndex;
+    //! End index of the string where this element has been parsed from.
+    int  endIndex;
+};
 
 /*! \internal \brief
  * Represents an element of a selection expression.