Add syntax to force selection string matching mode.
authorTeemu Murtola <teemu.murtola@gmail.com>
Fri, 24 Aug 2012 09:42:19 +0000 (12:42 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Tue, 28 Aug 2012 03:45:10 +0000 (06:45 +0300)
The selection syntax for string keyword matching no longer depends on
whether regular expression support is available.  Instead, an error is
now given if the string looks like a regexp (the logic for the deduction
is not changed), but regexp support is not available.  Added syntax to
force the string matching to use either literal, wildcard, or regexp
matching.

This change allows removing a few more direct prints to stderr (related
to #655).

Closes #938.

Change-Id: I7b998050c8b00b5f1229ed23a0a15685c514010f

12 files changed:
src/gromacs/selection/keywords.h
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.h
src/gromacs/selection/parser.y
src/gromacs/selection/parsetree.cpp
src/gromacs/selection/parsetree.h
src/gromacs/selection/selhelp.cpp
src/gromacs/selection/sm_keywords.cpp
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesForcedStringMatchingMode.xml [new file with mode: 0644]
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesRegexMatching.xml
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesWildcardMatching.xml [new file with mode: 0644]
src/gromacs/selection/tests/selectioncollection.cpp

index 70a6a4de419124135dc00695f797e990a9ca674c..a270ee11cae08e02bba9191a994775df06653477 100644 (file)
@@ -68,6 +68,11 @@ _gmx_selelem_set_kwpos_type(gmx::SelectionTreeElement *sel, const char *type);
 void
 _gmx_selelem_set_kwpos_flags(gmx::SelectionTreeElement *sel, int flags);
 
+/** Sets the string match type for string keyword evaluation. */
+void
+_gmx_selelem_set_kwstr_match_type(const gmx::SelectionTreeElementPointer &sel,
+                                  gmx::SelectionStringMatchType matchType);
+
 /** Does custom processing for parameters of the \c same selection method. */
 int
 _gmx_selelem_custom_init_same(struct gmx_ana_selmethod_t **method,
index 25b4a952a58bea83b50980efcfa327bbe67de8e9..69c4a006012f1370b4884d7cdad5aadc03ecd1e9 100644 (file)
@@ -198,6 +198,8 @@ typedef union YYSTYPE
     char                       *str;
     struct gmx_ana_selmethod_t *meth;
 
+    gmx::SelectionStringMatchType                smt;
+
     gmx::SelectionTreeElementPointer            *sel;
     gmx::SelectionParserValue                   *val;
     gmx::SelectionParserValueListPointer        *vlist;
@@ -207,7 +209,7 @@ typedef union YYSTYPE
 
 
 /* Line 293 of yacc.c  */
-#line 211 "parser.cpp"
+#line 213 "parser.cpp"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -243,7 +245,7 @@ void yypstate_delete ();
 
 
 /* Line 343 of yacc.c  */
-#line 247 "parser.cpp"
+#line 249 "parser.cpp"
 
 #ifdef short
 # undef short
@@ -441,13 +443,13 @@ union yyalloc
 #define YYLAST   361
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  49
+#define YYNTOKENS  51
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  26
+#define YYNNTS  27
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  89
+#define YYNRULES  93
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  148
+#define YYNSTATES  153
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -463,15 +465,15 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      42,    43,    36,    34,    45,    35,     2,    37,     2,     2,
+      42,    43,    36,    34,    47,    35,     2,    37,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    41,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    41,     2,    45,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    44,     2,    46,    39,     2,     2,     2,     2,     2,
+       2,    46,     2,    48,    39,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    47,     2,    48,     2,     2,     2,     2,
+       2,     2,     2,    49,     2,    50,    44,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -494,62 +496,65 @@ static const yytype_uint8 yytranslate[] =
 #if YYDEBUG
 /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
    YYRHS.  */
-static const yytype_uint8 yyprhs[] =
+static const yytype_uint16 yyprhs[] =
 {
        0,     0,     3,     4,     7,    10,    13,    14,    16,    18,
       20,    22,    25,    29,    33,    37,    40,    41,    44,    46,
       48,    52,    56,    58,    61,    63,    66,    68,    70,    72,
       74,    77,    81,    85,    89,    93,    96,    99,   101,   103,
-     106,   110,   114,   118,   120,   122,   125,   129,   133,   137,
-     141,   145,   148,   152,   156,   158,   161,   169,   173,   176,
-     180,   182,   184,   186,   188,   191,   192,   195,   198,   200,
-     204,   205,   208,   212,   214,   218,   220,   223,   227,   229,
-     231,   233,   235,   237,   239,   241,   243,   245,   249,   253
+     105,   107,   109,   112,   116,   121,   125,   129,   131,   133,
+     136,   140,   144,   148,   152,   156,   159,   163,   167,   169,
+     172,   180,   184,   187,   191,   193,   195,   197,   199,   202,
+     203,   206,   209,   211,   215,   216,   219,   223,   225,   229,
+     231,   234,   238,   240,   242,   244,   246,   248,   250,   252,
+     254,   256,   260,   264
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      50,     0,    -1,    -1,    50,    51,    -1,    52,    10,    -1,
-       1,    10,    -1,    -1,    53,    -1,     6,    -1,    59,    -1,
-      55,    -1,    59,    55,    -1,     9,    41,    60,    -1,     9,
-      41,    62,    -1,     9,    41,    64,    -1,     4,    54,    -1,
-      -1,    54,     5,    -1,    64,    -1,    60,    -1,    42,    55,
-      43,    -1,    55,    23,    65,    -1,     6,    -1,    35,     6,
-      -1,     7,    -1,    35,     7,    -1,    56,    -1,    57,    -1,
-       8,    -1,     9,    -1,    33,    60,    -1,    60,    32,    60,
-      -1,    60,    31,    60,    -1,    42,    60,    43,    -1,    62,
-      28,    62,    -1,    11,    59,    -1,    11,     6,    -1,    24,
-      -1,    18,    -1,    61,    19,    -1,    61,    17,    70,    -1,
-      61,    16,    70,    -1,    61,    21,    65,    -1,     6,    -1,
-       7,    -1,    61,    16,    -1,    61,    20,    65,    -1,    62,
-      34,    62,    -1,    62,    35,    62,    -1,    62,    36,    62,
-      -1,    62,    37,    62,    -1,    35,    62,    -1,    62,    39,
-      62,    -1,    42,    62,    43,    -1,    59,    -1,    61,    17,
-      -1,    44,    58,    45,    58,    45,    58,    46,    -1,    42,
-      64,    43,    -1,    22,    65,    -1,    18,    27,    60,    -1,
-      14,    -1,    13,    -1,    15,    -1,    66,    -1,    66,    26,
-      -1,    -1,    66,    67,    -1,    25,    68,    -1,    69,    -1,
-      47,    69,    48,    -1,    -1,    69,    72,    -1,    69,    45,
-      72,    -1,    71,    -1,    47,    71,    48,    -1,    73,    -1,
-      71,    73,    -1,    71,    45,    73,    -1,    60,    -1,    64,
-      -1,    62,    -1,    63,    -1,    74,    -1,    56,    -1,    57,
-      -1,    59,    -1,    74,    -1,    56,    12,    56,    -1,    56,
-      12,    57,    -1,    57,    12,    58,    -1
+      52,     0,    -1,    -1,    52,    53,    -1,    54,    10,    -1,
+       1,    10,    -1,    -1,    55,    -1,     6,    -1,    61,    -1,
+      57,    -1,    61,    57,    -1,     9,    41,    62,    -1,     9,
+      41,    65,    -1,     9,    41,    67,    -1,     4,    56,    -1,
+      -1,    56,     5,    -1,    67,    -1,    62,    -1,    42,    57,
+      43,    -1,    57,    23,    68,    -1,     6,    -1,    35,     6,
+      -1,     7,    -1,    35,     7,    -1,    58,    -1,    59,    -1,
+       8,    -1,     9,    -1,    33,    62,    -1,    62,    32,    62,
+      -1,    62,    31,    62,    -1,    42,    62,    43,    -1,    65,
+      28,    65,    -1,    11,    61,    -1,    11,     6,    -1,    24,
+      -1,    18,    -1,    44,    -1,    45,    -1,    41,    -1,    63,
+      19,    -1,    63,    17,    73,    -1,    63,    17,    64,    73,
+      -1,    63,    16,    73,    -1,    63,    21,    68,    -1,     6,
+      -1,     7,    -1,    63,    16,    -1,    63,    20,    68,    -1,
+      65,    34,    65,    -1,    65,    35,    65,    -1,    65,    36,
+      65,    -1,    65,    37,    65,    -1,    35,    65,    -1,    65,
+      39,    65,    -1,    42,    65,    43,    -1,    61,    -1,    63,
+      17,    -1,    46,    60,    47,    60,    47,    60,    48,    -1,
+      42,    67,    43,    -1,    22,    68,    -1,    18,    27,    62,
+      -1,    14,    -1,    13,    -1,    15,    -1,    69,    -1,    69,
+      26,    -1,    -1,    69,    70,    -1,    25,    71,    -1,    72,
+      -1,    49,    72,    50,    -1,    -1,    72,    75,    -1,    72,
+      47,    75,    -1,    74,    -1,    49,    74,    50,    -1,    76,
+      -1,    74,    76,    -1,    74,    47,    76,    -1,    62,    -1,
+      67,    -1,    65,    -1,    66,    -1,    77,    -1,    58,    -1,
+      59,    -1,    61,    -1,    77,    -1,    58,    12,    58,    -1,
+      58,    12,    59,    -1,    59,    12,    60,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   190,   190,   195,   206,   207,   229,   235,   241,   253,
-     266,   272,   279,   286,   293,   304,   313,   318,   329,   330,
-     337,   338,   352,   353,   357,   358,   361,   362,   365,   366,
-     374,   385,   396,   407,   411,   422,   430,   440,   441,   445,
-     453,   461,   472,   487,   498,   512,   520,   531,   537,   543,
-     549,   555,   561,   567,   574,   585,   600,   609,   613,   623,
-     637,   645,   653,   666,   668,   674,   679,   690,   699,   700,
-     705,   710,   718,   729,   730,   734,   740,   748,   758,   764,
-     770,   776,   782,   786,   792,   798,   805,   809,   815,   821
+       0,   193,   193,   198,   209,   210,   232,   238,   244,   256,
+     269,   275,   282,   289,   296,   307,   316,   321,   332,   333,
+     340,   341,   355,   356,   360,   361,   364,   365,   368,   369,
+     377,   388,   399,   410,   414,   425,   433,   443,   444,   449,
+     450,   451,   455,   463,   471,   479,   490,   505,   516,   530,
+     538,   549,   555,   561,   567,   573,   579,   585,   592,   603,
+     618,   627,   631,   641,   655,   663,   671,   684,   686,   692,
+     697,   708,   717,   718,   723,   728,   736,   747,   748,   752,
+     758,   766,   776,   782,   788,   794,   800,   804,   810,   816,
+     823,   827,   833,   839
 };
 #endif
 
@@ -565,13 +570,14 @@ static const char *const yytname[] =
   "METHOD_GROUP", "METHOD_POS", "MODIFIER", "EMPTY_POSMOD", "PARAM",
   "END_OF_METHOD", "OF", "CMP_OP", "PARAM_REDUCT", "XOR", "OR", "AND",
   "NOT", "'+'", "'-'", "'*'", "'/'", "UNARY_NEG", "'^'", "NUM_REDUCT",
-  "'='", "'('", "')'", "'['", "','", "']'", "'{'", "'}'", "$accept",
-  "commands", "command", "cmd_plain", "help_request", "help_topic",
-  "selection", "integer_number", "real_number", "number", "string",
-  "sel_expr", "pos_mod", "num_expr", "str_expr", "pos_expr",
-  "method_params", "method_param_list", "method_param", "value_list",
-  "value_list_contents", "basic_value_list", "basic_value_list_contents",
-  "value_item", "basic_value_item", "value_item_range", 0
+  "'='", "'('", "')'", "'~'", "'?'", "'['", "','", "']'", "'{'", "'}'",
+  "$accept", "commands", "command", "cmd_plain", "help_request",
+  "help_topic", "selection", "integer_number", "real_number", "number",
+  "string", "sel_expr", "pos_mod", "str_match_type", "num_expr",
+  "str_expr", "pos_expr", "method_params", "method_param_list",
+  "method_param", "value_list", "value_list_contents", "basic_value_list",
+  "basic_value_list_contents", "value_item", "basic_value_item",
+  "value_item_range", 0
 };
 #endif
 
@@ -584,22 +590,24 @@ static const yytype_uint16 yytoknum[] =
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,    43,    45,    42,    47,   289,    94,
-     290,    61,    40,    41,    91,    44,    93,   123,   125
+     290,    61,    40,    41,   126,    63,    91,    44,    93,   123,
+     125
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
-      52,    52,    52,    52,    52,    53,    54,    54,    55,    55,
-      55,    55,    56,    56,    57,    57,    58,    58,    59,    59,
-      60,    60,    60,    60,    60,    60,    60,    61,    61,    60,
-      60,    60,    60,    62,    62,    62,    62,    62,    62,    62,
-      62,    62,    62,    62,    63,    63,    64,    64,    64,    64,
-      60,    62,    64,    65,    65,    66,    66,    67,    68,    68,
-      69,    69,    69,    70,    70,    71,    71,    71,    72,    72,
-      72,    72,    72,    73,    73,    73,    73,    74,    74,    74
+       0,    51,    52,    52,    53,    53,    54,    54,    54,    54,
+      54,    54,    54,    54,    54,    55,    56,    56,    57,    57,
+      57,    57,    58,    58,    59,    59,    60,    60,    61,    61,
+      62,    62,    62,    62,    62,    62,    62,    63,    63,    64,
+      64,    64,    62,    62,    62,    62,    62,    65,    65,    65,
+      65,    65,    65,    65,    65,    65,    65,    65,    66,    66,
+      67,    67,    67,    67,    62,    65,    67,    68,    68,    69,
+      69,    70,    71,    71,    72,    72,    72,    73,    73,    74,
+      74,    74,    75,    75,    75,    75,    75,    76,    76,    76,
+      76,    77,    77,    77
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -608,12 +616,13 @@ static const yytype_uint8 yyr2[] =
        0,     2,     0,     2,     2,     2,     0,     1,     1,     1,
        1,     2,     3,     3,     3,     2,     0,     2,     1,     1,
        3,     3,     1,     2,     1,     2,     1,     1,     1,     1,
-       2,     3,     3,     3,     3,     2,     2,     1,     1,     2,
-       3,     3,     3,     1,     1,     2,     3,     3,     3,     3,
-       3,     2,     3,     3,     1,     2,     7,     3,     2,     3,
-       1,     1,     1,     1,     2,     0,     2,     2,     1,     3,
-       0,     2,     3,     1,     3,     1,     2,     3,     1,     1,
-       1,     1,     1,     1,     1,     1,     1,     3,     3,     3
+       2,     3,     3,     3,     3,     2,     2,     1,     1,     1,
+       1,     1,     2,     3,     4,     3,     3,     1,     1,     2,
+       3,     3,     3,     3,     3,     2,     3,     3,     1,     2,
+       7,     3,     2,     3,     1,     1,     1,     1,     2,     0,
+       2,     2,     1,     3,     0,     2,     3,     1,     3,     1,
+       2,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     3,     3,     3
 };
 
 /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@@ -621,59 +630,61 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       2,     0,     1,     0,    16,    43,    44,    28,    29,     0,
-      61,    60,    62,    38,    65,    37,     0,     0,     0,     0,
+       2,     0,     1,     0,    16,    47,    48,    28,    29,     0,
+      65,    64,    66,    38,    69,    37,     0,     0,     0,     0,
        3,     0,     7,    10,     9,    19,     0,     0,    18,     5,
-      15,     0,    36,    29,    35,     0,    58,    63,    43,    38,
-       0,    30,     0,     0,    51,     0,    19,     0,    18,    22,
-      24,     0,    26,    27,     0,     4,    65,    11,     0,     0,
-      45,     0,    39,    65,    65,     0,     0,     0,     0,     0,
-       0,    17,     0,    12,    13,    14,    59,    70,    64,    66,
-       0,     0,    45,    20,    33,    53,    57,    23,    25,     0,
-      21,    32,    31,     0,    83,    84,    85,    41,    73,    75,
-      86,    40,    46,    42,    34,    47,    48,    49,    50,    52,
-       0,    70,    67,    68,     0,     0,     0,     0,     0,    76,
-       0,    43,    44,     0,     0,     0,     0,    54,    78,     0,
-      80,    81,    79,    71,    82,     0,    74,    87,    88,    89,
-      77,    69,    43,    44,    72,    55,     0,    56
+      15,     0,    36,    29,    35,     0,    62,    67,    47,    38,
+       0,    30,     0,     0,    55,     0,    19,     0,    18,    22,
+      24,     0,    26,    27,     0,     4,    69,    11,     0,     0,
+      49,     0,    42,    69,    69,     0,     0,     0,     0,     0,
+       0,    17,     0,    12,    13,    14,    63,    74,    68,    70,
+       0,     0,    49,    20,    33,    57,    61,    23,    25,     0,
+      21,    32,    31,     0,    87,    88,    89,    45,    77,    79,
+      90,    41,    39,    40,     0,    43,    50,    46,    34,    51,
+      52,    53,    54,    56,     0,    74,    71,    72,     0,     0,
+       0,     0,     0,    80,    44,     0,    47,    48,     0,     0,
+       0,     0,    58,    82,     0,    84,    85,    83,    75,    86,
+       0,    78,    91,    92,    93,    81,    73,    47,    48,    76,
+      59,     0,    60
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
       -1,     1,    20,    21,    22,    30,    23,    94,    95,    54,
-      96,   128,    26,    27,   131,   132,    36,    37,    79,   112,
-     113,   101,    98,   133,    99,   100
+      96,   133,    26,   104,    27,   136,   137,    36,    37,    79,
+     116,   117,   105,    98,   138,    99,   100
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -83
+#define YYPACT_NINF -95
 static const yytype_int16 yypact[] =
 {
-     -83,   141,   -83,    -5,   -83,    13,   -83,   -83,   -23,   118,
-     -83,   -83,   -83,     4,   -83,   -83,   300,   316,   261,    15,
-     -83,    36,   -83,    40,   261,     8,   184,   198,   -83,   -83,
-      70,   286,   -83,   -83,   -83,   300,   -83,    44,   -83,   -83,
-     300,   -83,   316,    29,    62,   -19,    77,   159,    54,   -83,
-     -83,   131,   -83,   -83,    38,   -83,   -83,    40,   300,   300,
-      49,    58,   -83,   -83,   -83,   316,   316,   316,   316,   316,
-     316,   -83,   286,     8,   198,   -83,     8,    63,   -83,   -83,
-      77,   310,   -83,   -83,   -83,   -83,   -83,   -83,   -83,    15,
-     -83,    89,   -83,     7,   127,   134,   -83,   -83,   122,   -83,
-     -83,   -83,   -83,   -83,    79,    55,    55,    62,    62,    62,
-      54,   -83,   -83,   207,   113,     3,    15,    15,     7,   -83,
-     164,   150,   152,   319,   247,   127,   134,   -83,     8,   227,
-      79,   -83,   -83,   -83,   -83,    15,   -83,   -83,   -83,   -83,
-     -83,   -83,   154,   156,   -83,    58,    88,   -83
+     -95,   134,   -95,     2,   -95,     4,   -95,   -95,   -17,   145,
+     -95,   -95,   -95,     1,   -95,   -95,   283,   299,   246,    20,
+     -95,    23,   -95,    18,   246,    87,   323,   150,   -95,   -95,
+      44,   269,   -95,   -95,   -95,   283,   -95,    57,   -95,   -95,
+     283,   -95,   299,    78,    15,    19,   -22,   193,    58,   -95,
+     -95,   167,   -95,   -95,    59,   -95,   -95,    18,   283,   283,
+      81,    51,   -95,   -95,   -95,   299,   299,   299,   299,   299,
+     299,   -95,   269,    87,   150,   -95,    87,    61,   -95,   -95,
+     -22,   293,   -95,   -95,   -95,   -95,   -95,   -95,   -95,    20,
+     -95,    76,   -95,    11,   102,   108,   -95,   -95,   187,   -95,
+     -95,   -95,   -95,   -95,   153,   -95,   -95,   -95,   315,   161,
+     161,    15,    15,    15,    58,   -95,   -95,   202,    82,    -3,
+      20,    20,    11,   -95,   -95,   157,   119,   127,   313,   232,
+     102,   108,   -95,    87,   340,   315,   -95,   -95,   -95,   -95,
+      20,   -95,   -95,   -95,   -95,   -95,   -95,   138,   143,   -95,
+      51,    98,   -95
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -83,   -83,   -83,   -83,   -83,   -83,    10,   -18,   -13,   -82,
-      -1,     1,    20,    12,   -83,     2,    97,   -83,   -83,   -83,
-      69,   109,    91,    57,   -71,   -52
+     -95,   -95,   -95,   -95,   -95,   -95,    67,   -18,    -8,   -87,
+      -1,    21,     8,   -95,    -2,   -95,    12,    41,   -95,   -95,
+     -95,    42,   -53,    84,    53,   -50,   -94
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -682,111 +693,112 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -26
 static const yytype_int16 yytable[] =
 {
-      24,    52,    25,    28,    56,    29,    53,   114,    34,    49,
-      50,     7,    33,    49,    50,     7,    33,    41,    31,    46,
-      48,    49,    50,    -8,    83,    25,    28,   119,    45,    44,
-      47,    35,    73,    75,    57,   139,    76,    43,    51,    58,
-      59,    80,    51,    74,   119,    82,    55,   140,   118,    63,
-      51,   136,    47,   146,    81,    49,    50,     7,    33,    91,
-      92,   134,    43,    56,    49,    50,     7,    33,   134,    77,
-      78,    52,   134,    80,   110,    71,    53,   104,   105,   106,
-     107,   108,   109,    89,    47,    43,    43,    43,    43,    43,
-      43,    68,    69,    51,    70,   125,    93,    86,   137,    52,
-     126,    70,   125,   138,    53,    93,   125,   126,    58,    59,
-     111,   126,   127,    66,    67,    68,    69,    52,    70,   127,
-      84,    59,    53,   127,    32,   130,     7,    33,    49,    50,
-       7,    33,   130,   129,   147,    44,   130,    87,    88,   116,
-     129,     2,     3,    43,   129,     4,   117,     5,     6,     7,
-       8,    -6,     9,    90,    10,    11,    12,    51,   135,    13,
-     102,   103,   -22,    14,   -24,    15,   -23,   118,   -25,    97,
-     121,   122,     7,    33,    16,     9,    17,    10,    11,    12,
-     120,   144,    13,    18,   115,    19,    14,    65,    15,     0,
-       0,     0,     0,    66,    67,    68,    69,    16,    70,   123,
-      60,    61,    85,    62,    63,    64,    72,     0,    19,   124,
-       0,     0,   141,   121,   122,     7,    33,     0,     9,     0,
-      10,    11,    12,     0,     0,    13,    65,     0,     0,    14,
-       0,    15,    66,    67,    68,    69,     0,    70,     0,     0,
-      16,     0,   123,    60,   145,     0,    62,    63,    64,    72,
-       0,    19,   124,   121,   122,     7,    33,     0,     9,     0,
-      10,    11,    12,     0,     0,    13,     0,    38,     6,    14,
-       0,    15,     9,     0,    10,    11,    12,     0,     0,    13,
-      16,     0,   123,    14,     0,    15,     0,     0,     0,    72,
-       0,    19,    38,     6,    16,     0,    17,     9,     0,    10,
-      11,    12,     0,    18,    13,    19,    38,     6,    14,     0,
-      15,     9,     0,    10,    11,     0,     0,     0,    39,    16,
-       0,    17,    38,     6,    15,   142,   143,     0,    72,    10,
-      19,     0,    10,    16,    39,    17,     0,    39,     0,     0,
-      15,     0,    40,    15,    66,    67,    68,    69,     0,    70,
-       0,    17,     0,    85,    17,     0,     0,     0,    42,     0,
-       0,    42
+      24,    52,   118,    49,    50,     7,    33,    97,    34,    58,
+      59,    53,    29,    28,    -8,    44,    47,    49,    50,     7,
+      33,    84,    25,   139,    31,    43,    49,    50,    35,    74,
+      48,   139,    51,    55,   144,   139,    28,    41,    47,    46,
+      81,    56,    56,    75,   122,    25,    51,   141,   123,    71,
+      43,   124,    73,   151,    70,    51,    76,    49,    50,     7,
+      33,    80,    83,   108,   109,   110,   111,   112,   113,   123,
+      47,    52,   145,    43,    43,    43,    43,    43,    43,    91,
+      92,    53,    77,    78,   114,    45,    51,    49,    50,     7,
+      33,    57,   101,    80,    82,   102,   103,    90,    63,   130,
+      93,    86,   142,    52,   106,   107,    89,   130,    59,   131,
+     115,   130,   143,    53,   120,   135,   132,   131,    58,    59,
+     121,   131,    52,   135,   132,   134,    44,   135,   132,   140,
+      93,   -22,    53,   134,     2,     3,    43,   134,     4,   -24,
+       5,     6,     7,     8,    -6,     9,   152,    10,    11,    12,
+     -23,    32,    13,     7,    33,   -25,    14,   125,    15,    49,
+      50,     7,    33,   126,   127,     7,    33,    16,     9,    17,
+      10,    11,    12,    87,    88,    13,    18,   119,    65,    14,
+      19,    15,   149,     0,    66,    67,    68,    69,    51,    70,
+      16,     0,   128,    49,    50,     7,    33,    68,    69,    72,
+      70,     0,    93,    19,   129,     0,     0,   146,   126,   127,
+       7,    33,     0,     9,     0,    10,    11,    12,     0,     0,
+      13,    65,    51,     0,    14,     0,    15,    66,    67,    68,
+      69,     0,    70,     0,   122,    16,    85,   128,   126,   127,
+       7,    33,     0,     9,    72,    10,    11,    12,    19,   129,
+      13,     0,    38,     6,    14,     0,    15,     9,     0,    10,
+      11,    12,     0,     0,    13,    16,     0,   128,    14,     0,
+      15,     0,     0,     0,    72,    38,     6,     0,    19,    16,
+       9,    17,    10,    11,    12,     0,     0,    13,    18,    38,
+       6,    14,    19,    15,     9,     0,    10,    11,     0,     0,
+       0,    39,    16,     0,    17,    38,     6,    15,     0,     0,
+       0,    72,    10,     0,     0,    19,    16,    39,    17,   147,
+     148,     0,     0,    15,     0,    40,    10,    66,    67,    68,
+      69,    39,    70,     0,    17,     0,    85,    15,     0,    60,
+      61,    42,    62,    63,    64,     0,     0,     0,    17,    66,
+      67,    68,    69,     0,    70,    42,    60,   150,     0,    62,
+      63,    64
 };
 
 #define yypact_value_is_default(yystate) \
-  ((yystate) == (-83))
+  ((yystate) == (-95))
 
 #define yytable_value_is_error(yytable_value) \
   YYID (0)
 
 static const yytype_int16 yycheck[] =
 {
-       1,    19,     1,     1,    23,    10,    19,    89,     9,     6,
-       7,     8,     9,     6,     7,     8,     9,    16,    41,    18,
-      18,     6,     7,    10,    43,    24,    24,    98,    18,    17,
-      18,    27,    31,    31,    24,   117,    35,    17,    35,    31,
-      32,    40,    35,    31,   115,    16,    10,   118,    45,    20,
-      35,    48,    40,   135,    42,     6,     7,     8,     9,    58,
-      59,   113,    42,    23,     6,     7,     8,     9,   120,    25,
-      26,    89,   124,    72,    72,     5,    89,    65,    66,    67,
-      68,    69,    70,    45,    72,    65,    66,    67,    68,    69,
-      70,    36,    37,    35,    39,   113,    47,    43,   116,   117,
-     113,    39,   120,   116,   117,    47,   124,   120,    31,    32,
-      47,   124,   113,    34,    35,    36,    37,   135,    39,   120,
-      43,    32,   135,   124,     6,   113,     8,     9,     6,     7,
-       8,     9,   120,   113,    46,   123,   124,     6,     7,    12,
-     120,     0,     1,   123,   124,     4,    12,     6,     7,     8,
-       9,    10,    11,    56,    13,    14,    15,    35,    45,    18,
-      63,    64,    12,    22,    12,    24,    12,    45,    12,    60,
-       6,     7,     8,     9,    33,    11,    35,    13,    14,    15,
-     111,   124,    18,    42,    93,    44,    22,    28,    24,    -1,
-      -1,    -1,    -1,    34,    35,    36,    37,    33,    39,    35,
-      16,    17,    43,    19,    20,    21,    42,    -1,    44,    45,
-      -1,    -1,    48,     6,     7,     8,     9,    -1,    11,    -1,
-      13,    14,    15,    -1,    -1,    18,    28,    -1,    -1,    22,
-      -1,    24,    34,    35,    36,    37,    -1,    39,    -1,    -1,
-      33,    -1,    35,    16,    17,    -1,    19,    20,    21,    42,
-      -1,    44,    45,     6,     7,     8,     9,    -1,    11,    -1,
-      13,    14,    15,    -1,    -1,    18,    -1,     6,     7,    22,
-      -1,    24,    11,    -1,    13,    14,    15,    -1,    -1,    18,
-      33,    -1,    35,    22,    -1,    24,    -1,    -1,    -1,    42,
-      -1,    44,     6,     7,    33,    -1,    35,    11,    -1,    13,
-      14,    15,    -1,    42,    18,    44,     6,     7,    22,    -1,
-      24,    11,    -1,    13,    14,    -1,    -1,    -1,    18,    33,
-      -1,    35,     6,     7,    24,     6,     7,    -1,    42,    13,
-      44,    -1,    13,    33,    18,    35,    -1,    18,    -1,    -1,
-      24,    -1,    42,    24,    34,    35,    36,    37,    -1,    39,
-      -1,    35,    -1,    43,    35,    -1,    -1,    -1,    42,    -1,
-      -1,    42
+       1,    19,    89,     6,     7,     8,     9,    60,     9,    31,
+      32,    19,    10,     1,    10,    17,    18,     6,     7,     8,
+       9,    43,     1,   117,    41,    17,     6,     7,    27,    31,
+      18,   125,    35,    10,   121,   129,    24,    16,    40,    18,
+      42,    23,    23,    31,    47,    24,    35,    50,    98,     5,
+      42,   104,    31,   140,    39,    35,    35,     6,     7,     8,
+       9,    40,    43,    65,    66,    67,    68,    69,    70,   119,
+      72,    89,   122,    65,    66,    67,    68,    69,    70,    58,
+      59,    89,    25,    26,    72,    18,    35,     6,     7,     8,
+       9,    24,    41,    72,    16,    44,    45,    56,    20,   117,
+      49,    43,   120,   121,    63,    64,    47,   125,    32,   117,
+      49,   129,   120,   121,    12,   117,   117,   125,    31,    32,
+      12,   129,   140,   125,   125,   117,   128,   129,   129,    47,
+      49,    12,   140,   125,     0,     1,   128,   129,     4,    12,
+       6,     7,     8,     9,    10,    11,    48,    13,    14,    15,
+      12,     6,    18,     8,     9,    12,    22,   115,    24,     6,
+       7,     8,     9,     6,     7,     8,     9,    33,    11,    35,
+      13,    14,    15,     6,     7,    18,    42,    93,    28,    22,
+      46,    24,   129,    -1,    34,    35,    36,    37,    35,    39,
+      33,    -1,    35,     6,     7,     8,     9,    36,    37,    42,
+      39,    -1,    49,    46,    47,    -1,    -1,    50,     6,     7,
+       8,     9,    -1,    11,    -1,    13,    14,    15,    -1,    -1,
+      18,    28,    35,    -1,    22,    -1,    24,    34,    35,    36,
+      37,    -1,    39,    -1,    47,    33,    43,    35,     6,     7,
+       8,     9,    -1,    11,    42,    13,    14,    15,    46,    47,
+      18,    -1,     6,     7,    22,    -1,    24,    11,    -1,    13,
+      14,    15,    -1,    -1,    18,    33,    -1,    35,    22,    -1,
+      24,    -1,    -1,    -1,    42,     6,     7,    -1,    46,    33,
+      11,    35,    13,    14,    15,    -1,    -1,    18,    42,     6,
+       7,    22,    46,    24,    11,    -1,    13,    14,    -1,    -1,
+      -1,    18,    33,    -1,    35,     6,     7,    24,    -1,    -1,
+      -1,    42,    13,    -1,    -1,    46,    33,    18,    35,     6,
+       7,    -1,    -1,    24,    -1,    42,    13,    34,    35,    36,
+      37,    18,    39,    -1,    35,    -1,    43,    24,    -1,    16,
+      17,    42,    19,    20,    21,    -1,    -1,    -1,    35,    34,
+      35,    36,    37,    -1,    39,    42,    16,    17,    -1,    19,
+      20,    21
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    50,     0,     1,     4,     6,     7,     8,     9,    11,
-      13,    14,    15,    18,    22,    24,    33,    35,    42,    44,
-      51,    52,    53,    55,    59,    60,    61,    62,    64,    10,
-      54,    41,     6,     9,    59,    27,    65,    66,     6,    18,
-      42,    60,    42,    61,    62,    55,    60,    62,    64,     6,
-       7,    35,    56,    57,    58,    10,    23,    55,    31,    32,
+       0,    52,     0,     1,     4,     6,     7,     8,     9,    11,
+      13,    14,    15,    18,    22,    24,    33,    35,    42,    46,
+      53,    54,    55,    57,    61,    62,    63,    65,    67,    10,
+      56,    41,     6,     9,    61,    27,    68,    69,     6,    18,
+      42,    62,    42,    63,    65,    57,    62,    65,    67,     6,
+       7,    35,    58,    59,    60,    10,    23,    57,    31,    32,
       16,    17,    19,    20,    21,    28,    34,    35,    36,    37,
-      39,     5,    42,    60,    62,    64,    60,    25,    26,    67,
-      60,    62,    16,    43,    43,    43,    43,     6,     7,    45,
-      65,    60,    60,    47,    56,    57,    59,    70,    71,    73,
-      74,    70,    65,    65,    62,    62,    62,    62,    62,    62,
-      64,    47,    68,    69,    58,    71,    12,    12,    45,    73,
-      69,     6,     7,    35,    45,    56,    57,    59,    60,    61,
-      62,    63,    64,    72,    74,    45,    48,    56,    57,    58,
-      73,    48,     6,     7,    72,    17,    58,    46
+      39,     5,    42,    62,    65,    67,    62,    25,    26,    70,
+      62,    65,    16,    43,    43,    43,    43,     6,     7,    47,
+      68,    62,    62,    49,    58,    59,    61,    73,    74,    76,
+      77,    41,    44,    45,    64,    73,    68,    68,    65,    65,
+      65,    65,    65,    65,    67,    49,    71,    72,    60,    74,
+      12,    12,    47,    76,    73,    72,     6,     7,    35,    47,
+      58,    59,    61,    62,    63,    65,    66,    67,    75,    77,
+      47,    50,    58,    59,    60,    76,    50,     6,     7,    75,
+      17,    60,    48
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1331,245 +1343,245 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
       case 5: /* "HELP_TOPIC" */
 
 /* Line 1391 of yacc.c  */
-#line 169 "parser.y"
+#line 172 "parser.y"
        { free((yyvaluep->str));        };
 
 /* Line 1391 of yacc.c  */
-#line 1339 "parser.cpp"
+#line 1351 "parser.cpp"
        break;
       case 8: /* "STR" */
 
 /* Line 1391 of yacc.c  */
-#line 169 "parser.y"
+#line 172 "parser.y"
        { free((yyvaluep->str));        };
 
 /* Line 1391 of yacc.c  */
-#line 1348 "parser.cpp"
+#line 1360 "parser.cpp"
        break;
       case 9: /* "IDENTIFIER" */
 
 /* Line 1391 of yacc.c  */
-#line 169 "parser.y"
+#line 172 "parser.y"
        { free((yyvaluep->str));        };
 
 /* Line 1391 of yacc.c  */
-#line 1357 "parser.cpp"
+#line 1369 "parser.cpp"
        break;
       case 18: /* "KEYWORD_POS" */
 
 /* Line 1391 of yacc.c  */
-#line 169 "parser.y"
+#line 172 "parser.y"
        { free((yyvaluep->str));        };
 
 /* Line 1391 of yacc.c  */
-#line 1366 "parser.cpp"
+#line 1378 "parser.cpp"
        break;
       case 25: /* "PARAM" */
 
 /* Line 1391 of yacc.c  */
-#line 170 "parser.y"
+#line 173 "parser.y"
        { if((yyvaluep->str)) free((yyvaluep->str)); };
 
 /* Line 1391 of yacc.c  */
-#line 1375 "parser.cpp"
+#line 1387 "parser.cpp"
        break;
       case 28: /* "CMP_OP" */
 
 /* Line 1391 of yacc.c  */
-#line 169 "parser.y"
+#line 172 "parser.y"
        { free((yyvaluep->str));        };
 
 /* Line 1391 of yacc.c  */
-#line 1384 "parser.cpp"
+#line 1396 "parser.cpp"
        break;
-      case 50: /* "commands" */
+      case 52: /* "commands" */
 
 /* Line 1391 of yacc.c  */
-#line 171 "parser.y"
+#line 174 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1393 "parser.cpp"
+#line 1405 "parser.cpp"
        break;
-      case 51: /* "command" */
+      case 53: /* "command" */
 
 /* Line 1391 of yacc.c  */
-#line 171 "parser.y"
+#line 174 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1402 "parser.cpp"
+#line 1414 "parser.cpp"
        break;
-      case 52: /* "cmd_plain" */
+      case 54: /* "cmd_plain" */
 
 /* Line 1391 of yacc.c  */
-#line 171 "parser.y"
+#line 174 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1411 "parser.cpp"
+#line 1423 "parser.cpp"
        break;
-      case 54: /* "help_topic" */
+      case 56: /* "help_topic" */
 
 /* Line 1391 of yacc.c  */
-#line 176 "parser.y"
+#line 179 "parser.y"
        { delete (yyvaluep->vlist);       };
 
 /* Line 1391 of yacc.c  */
-#line 1420 "parser.cpp"
+#line 1432 "parser.cpp"
        break;
-      case 55: /* "selection" */
+      case 57: /* "selection" */
 
 /* Line 1391 of yacc.c  */
-#line 171 "parser.y"
+#line 174 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1429 "parser.cpp"
+#line 1441 "parser.cpp"
        break;
-      case 59: /* "string" */
+      case 61: /* "string" */
 
 /* Line 1391 of yacc.c  */
-#line 169 "parser.y"
+#line 172 "parser.y"
        { free((yyvaluep->str));        };
 
 /* Line 1391 of yacc.c  */
-#line 1438 "parser.cpp"
+#line 1450 "parser.cpp"
        break;
-      case 60: /* "sel_expr" */
+      case 62: /* "sel_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 172 "parser.y"
+#line 175 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1447 "parser.cpp"
+#line 1459 "parser.cpp"
        break;
-      case 61: /* "pos_mod" */
+      case 63: /* "pos_mod" */
 
 /* Line 1391 of yacc.c  */
-#line 170 "parser.y"
+#line 173 "parser.y"
        { if((yyvaluep->str)) free((yyvaluep->str)); };
 
 /* Line 1391 of yacc.c  */
-#line 1456 "parser.cpp"
+#line 1468 "parser.cpp"
        break;
-      case 62: /* "num_expr" */
+      case 65: /* "num_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 172 "parser.y"
+#line 175 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1465 "parser.cpp"
+#line 1477 "parser.cpp"
        break;
-      case 63: /* "str_expr" */
+      case 66: /* "str_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 172 "parser.y"
+#line 175 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1474 "parser.cpp"
+#line 1486 "parser.cpp"
        break;
-      case 64: /* "pos_expr" */
+      case 67: /* "pos_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 172 "parser.y"
+#line 175 "parser.y"
        { delete (yyvaluep->sel);       };
 
 /* Line 1391 of yacc.c  */
-#line 1483 "parser.cpp"
+#line 1495 "parser.cpp"
        break;
-      case 65: /* "method_params" */
+      case 68: /* "method_params" */
 
 /* Line 1391 of yacc.c  */
-#line 173 "parser.y"
+#line 176 "parser.y"
        { delete (yyvaluep->plist);       };
 
 /* Line 1391 of yacc.c  */
-#line 1492 "parser.cpp"
+#line 1504 "parser.cpp"
        break;
-      case 66: /* "method_param_list" */
+      case 69: /* "method_param_list" */
 
 /* Line 1391 of yacc.c  */
-#line 173 "parser.y"
+#line 176 "parser.y"
        { delete (yyvaluep->plist);       };
 
 /* Line 1391 of yacc.c  */
-#line 1501 "parser.cpp"
+#line 1513 "parser.cpp"
        break;
-      case 67: /* "method_param" */
+      case 70: /* "method_param" */
 
 /* Line 1391 of yacc.c  */
-#line 173 "parser.y"
+#line 176 "parser.y"
        { delete (yyvaluep->param);       };
 
 /* Line 1391 of yacc.c  */
-#line 1510 "parser.cpp"
+#line 1522 "parser.cpp"
        break;
-      case 68: /* "value_list" */
+      case 71: /* "value_list" */
 
 /* Line 1391 of yacc.c  */
-#line 174 "parser.y"
+#line 177 "parser.y"
        { delete (yyvaluep->vlist);       };
 
 /* Line 1391 of yacc.c  */
-#line 1519 "parser.cpp"
+#line 1531 "parser.cpp"
        break;
-      case 69: /* "value_list_contents" */
+      case 72: /* "value_list_contents" */
 
 /* Line 1391 of yacc.c  */
-#line 174 "parser.y"
+#line 177 "parser.y"
        { delete (yyvaluep->vlist);       };
 
 /* Line 1391 of yacc.c  */
-#line 1528 "parser.cpp"
+#line 1540 "parser.cpp"
        break;
-      case 70: /* "basic_value_list" */
+      case 73: /* "basic_value_list" */
 
 /* Line 1391 of yacc.c  */
-#line 174 "parser.y"
+#line 177 "parser.y"
        { delete (yyvaluep->vlist);       };
 
 /* Line 1391 of yacc.c  */
-#line 1537 "parser.cpp"
+#line 1549 "parser.cpp"
        break;
-      case 71: /* "basic_value_list_contents" */
+      case 74: /* "basic_value_list_contents" */
 
 /* Line 1391 of yacc.c  */
-#line 174 "parser.y"
+#line 177 "parser.y"
        { delete (yyvaluep->vlist);       };
 
 /* Line 1391 of yacc.c  */
-#line 1546 "parser.cpp"
+#line 1558 "parser.cpp"
        break;
-      case 72: /* "value_item" */
+      case 75: /* "value_item" */
 
 /* Line 1391 of yacc.c  */
-#line 175 "parser.y"
+#line 178 "parser.y"
        { delete (yyvaluep->val);       };
 
 /* Line 1391 of yacc.c  */
-#line 1555 "parser.cpp"
+#line 1567 "parser.cpp"
        break;
-      case 73: /* "basic_value_item" */
+      case 76: /* "basic_value_item" */
 
 /* Line 1391 of yacc.c  */
-#line 175 "parser.y"
+#line 178 "parser.y"
        { delete (yyvaluep->val);       };
 
 /* Line 1391 of yacc.c  */
-#line 1564 "parser.cpp"
+#line 1576 "parser.cpp"
        break;
-      case 74: /* "value_item_range" */
+      case 77: /* "value_item_range" */
 
 /* Line 1391 of yacc.c  */
-#line 175 "parser.y"
+#line 178 "parser.y"
        { delete (yyvaluep->val);       };
 
 /* Line 1391 of yacc.c  */
-#line 1573 "parser.cpp"
+#line 1585 "parser.cpp"
        break;
 
       default:
@@ -1918,7 +1930,7 @@ yyreduce:
         case 2:
 
 /* Line 1806 of yacc.c  */
-#line 190 "parser.y"
+#line 193 "parser.y"
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
@@ -1929,7 +1941,7 @@ yyreduce:
   case 3:
 
 /* Line 1806 of yacc.c  */
-#line 196 "parser.y"
+#line 199 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_append_selection(get((yyvsp[(2) - (2)].sel)), get((yyvsp[(1) - (2)].sel)), scanner));
@@ -1942,14 +1954,14 @@ yyreduce:
   case 4:
 
 /* Line 1806 of yacc.c  */
-#line 206 "parser.y"
+#line 209 "parser.y"
     { (yyval.sel) = (yyvsp[(1) - (2)].sel); }
     break;
 
   case 5:
 
 /* Line 1806 of yacc.c  */
-#line 208 "parser.y"
+#line 211 "parser.y"
     {
                  BEGIN_ACTION;
                  _gmx_selparser_error(scanner, "invalid selection '%s'",
@@ -1972,7 +1984,7 @@ yyreduce:
   case 6:
 
 /* Line 1806 of yacc.c  */
-#line 229 "parser.y"
+#line 232 "parser.y"
     {
                  BEGIN_ACTION;
                  _gmx_sel_handle_empty_cmd(scanner);
@@ -1984,7 +1996,7 @@ yyreduce:
   case 7:
 
 /* Line 1806 of yacc.c  */
-#line 236 "parser.y"
+#line 239 "parser.y"
     {
                  BEGIN_ACTION;
                  set_empty((yyval.sel));
@@ -1995,7 +2007,7 @@ yyreduce:
   case 8:
 
 /* Line 1806 of yacc.c  */
-#line 242 "parser.y"
+#line 245 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer s
@@ -2012,7 +2024,7 @@ yyreduce:
   case 9:
 
 /* Line 1806 of yacc.c  */
-#line 254 "parser.y"
+#line 257 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (1)].str));
@@ -2030,7 +2042,7 @@ yyreduce:
   case 10:
 
 /* Line 1806 of yacc.c  */
-#line 267 "parser.y"
+#line 270 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[(1) - (1)].sel)), scanner));
@@ -2041,7 +2053,7 @@ yyreduce:
   case 11:
 
 /* Line 1806 of yacc.c  */
-#line 273 "parser.y"
+#line 276 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (2)].str));
@@ -2053,7 +2065,7 @@ yyreduce:
   case 12:
 
 /* Line 1806 of yacc.c  */
-#line 280 "parser.y"
+#line 283 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2065,7 +2077,7 @@ yyreduce:
   case 13:
 
 /* Line 1806 of yacc.c  */
-#line 287 "parser.y"
+#line 290 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2077,7 +2089,7 @@ yyreduce:
   case 14:
 
 /* Line 1806 of yacc.c  */
-#line 294 "parser.y"
+#line 297 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
@@ -2089,7 +2101,7 @@ yyreduce:
   case 15:
 
 /* Line 1806 of yacc.c  */
-#line 305 "parser.y"
+#line 308 "parser.y"
     {
                  BEGIN_ACTION;
                  _gmx_sel_handle_help_cmd(get((yyvsp[(2) - (2)].vlist)), scanner);
@@ -2100,7 +2112,7 @@ yyreduce:
   case 16:
 
 /* Line 1806 of yacc.c  */
-#line 313 "parser.y"
+#line 316 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
@@ -2111,7 +2123,7 @@ yyreduce:
   case 17:
 
 /* Line 1806 of yacc.c  */
-#line 319 "parser.y"
+#line 322 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2124,14 +2136,14 @@ yyreduce:
   case 18:
 
 /* Line 1806 of yacc.c  */
-#line 329 "parser.y"
+#line 332 "parser.y"
     { (yyval.sel) = (yyvsp[(1) - (1)].sel); }
     break;
 
   case 19:
 
 /* Line 1806 of yacc.c  */
-#line 331 "parser.y"
+#line 334 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(1) - (1)].sel)), NULL, scanner));
@@ -2143,14 +2155,14 @@ yyreduce:
   case 20:
 
 /* Line 1806 of yacc.c  */
-#line 337 "parser.y"
+#line 340 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 21:
 
 /* Line 1806 of yacc.c  */
-#line 339 "parser.y"
+#line 342 "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));
@@ -2162,63 +2174,63 @@ yyreduce:
   case 22:
 
 /* Line 1806 of yacc.c  */
-#line 352 "parser.y"
+#line 355 "parser.y"
     { (yyval.i) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 23:
 
 /* Line 1806 of yacc.c  */
-#line 353 "parser.y"
+#line 356 "parser.y"
     { (yyval.i) = -(yyvsp[(2) - (2)].i); }
     break;
 
   case 24:
 
 /* Line 1806 of yacc.c  */
-#line 357 "parser.y"
+#line 360 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 25:
 
 /* Line 1806 of yacc.c  */
-#line 358 "parser.y"
+#line 361 "parser.y"
     { (yyval.r) = -(yyvsp[(2) - (2)].r); }
     break;
 
   case 26:
 
 /* Line 1806 of yacc.c  */
-#line 361 "parser.y"
+#line 364 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 27:
 
 /* Line 1806 of yacc.c  */
-#line 362 "parser.y"
+#line 365 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 28:
 
 /* Line 1806 of yacc.c  */
-#line 365 "parser.y"
+#line 368 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 29:
 
 /* Line 1806 of yacc.c  */
-#line 366 "parser.y"
+#line 369 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 30:
 
 /* Line 1806 of yacc.c  */
-#line 375 "parser.y"
+#line 378 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg(get((yyvsp[(2) - (2)].sel)));
@@ -2234,7 +2246,7 @@ yyreduce:
   case 31:
 
 /* Line 1806 of yacc.c  */
-#line 386 "parser.y"
+#line 389 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
@@ -2250,7 +2262,7 @@ yyreduce:
   case 32:
 
 /* Line 1806 of yacc.c  */
-#line 397 "parser.y"
+#line 400 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
@@ -2266,14 +2278,14 @@ yyreduce:
   case 33:
 
 /* Line 1806 of yacc.c  */
-#line 407 "parser.y"
+#line 410 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 34:
 
 /* Line 1806 of yacc.c  */
-#line 412 "parser.y"
+#line 415 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree opGuard((yyvsp[(2) - (3)].str));
@@ -2286,7 +2298,7 @@ yyreduce:
   case 35:
 
 /* Line 1806 of yacc.c  */
-#line 423 "parser.y"
+#line 426 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(2) - (2)].str));
@@ -2299,7 +2311,7 @@ yyreduce:
   case 36:
 
 /* Line 1806 of yacc.c  */
-#line 431 "parser.y"
+#line 434 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner));
@@ -2311,21 +2323,42 @@ yyreduce:
   case 37:
 
 /* Line 1806 of yacc.c  */
-#line 440 "parser.y"
+#line 443 "parser.y"
     { (yyval.str) = NULL; }
     break;
 
   case 38:
 
 /* Line 1806 of yacc.c  */
-#line 441 "parser.y"
+#line 444 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str);   }
     break;
 
   case 39:
 
 /* Line 1806 of yacc.c  */
-#line 446 "parser.y"
+#line 449 "parser.y"
+    { (yyval.smt) = gmx::eStringMatchType_RegularExpression; }
+    break;
+
+  case 40:
+
+/* Line 1806 of yacc.c  */
+#line 450 "parser.y"
+    { (yyval.smt) = gmx::eStringMatchType_Wildcard; }
+    break;
+
+  case 41:
+
+/* Line 1806 of yacc.c  */
+#line 451 "parser.y"
+    { (yyval.smt) = gmx::eStringMatchType_Exact; }
+    break;
+
+  case 42:
+
+/* Line 1806 of yacc.c  */
+#line 456 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2335,23 +2368,36 @@ yyreduce:
              }
     break;
 
-  case 40:
+  case 43:
 
 /* Line 1806 of yacc.c  */
-#line 454 "parser.y"
+#line 464 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].vlist)), (yyvsp[(1) - (3)].str), scanner));
+                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[(2) - (3)].meth), gmx::eStringMatchType_Auto, get((yyvsp[(3) - (3)].vlist)), (yyvsp[(1) - (3)].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
 
-  case 41:
+  case 44:
+
+/* Line 1806 of yacc.c  */
+#line 472 "parser.y"
+    {
+                 BEGIN_ACTION;
+                 scoped_ptr_sfree posmodGuard((yyvsp[(1) - (4)].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_strmatch((yyvsp[(2) - (4)].meth), (yyvsp[(3) - (4)].smt), get((yyvsp[(4) - (4)].vlist)), (yyvsp[(1) - (4)].str), scanner));
+                 CHECK_SEL((yyval.sel));
+                 END_ACTION;
+             }
+    break;
+
+  case 45:
 
 /* Line 1806 of yacc.c  */
-#line 462 "parser.y"
+#line 480 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2361,10 +2407,10 @@ yyreduce:
              }
     break;
 
-  case 42:
+  case 46:
 
 /* Line 1806 of yacc.c  */
-#line 473 "parser.y"
+#line 491 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2374,10 +2420,10 @@ yyreduce:
              }
     break;
 
-  case 43:
+  case 47:
 
 /* Line 1806 of yacc.c  */
-#line 488 "parser.y"
+#line 506 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2390,10 +2436,10 @@ yyreduce:
              }
     break;
 
-  case 44:
+  case 48:
 
 /* Line 1806 of yacc.c  */
-#line 499 "parser.y"
+#line 517 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2406,10 +2452,10 @@ yyreduce:
              }
     break;
 
-  case 45:
+  case 49:
 
 /* Line 1806 of yacc.c  */
-#line 513 "parser.y"
+#line 531 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2419,10 +2465,10 @@ yyreduce:
              }
     break;
 
-  case 46:
+  case 50:
 
 /* Line 1806 of yacc.c  */
-#line 521 "parser.y"
+#line 539 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (3)].str));
@@ -2432,10 +2478,10 @@ yyreduce:
              }
     break;
 
-  case 47:
+  case 51:
 
 /* Line 1806 of yacc.c  */
-#line 532 "parser.y"
+#line 550 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
@@ -2443,10 +2489,10 @@ yyreduce:
              }
     break;
 
-  case 48:
+  case 52:
 
 /* Line 1806 of yacc.c  */
-#line 538 "parser.y"
+#line 556 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
@@ -2454,10 +2500,10 @@ yyreduce:
              }
     break;
 
-  case 49:
+  case 53:
 
 /* Line 1806 of yacc.c  */
-#line 544 "parser.y"
+#line 562 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
@@ -2465,10 +2511,10 @@ yyreduce:
              }
     break;
 
-  case 50:
+  case 54:
 
 /* Line 1806 of yacc.c  */
-#line 550 "parser.y"
+#line 568 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
@@ -2476,10 +2522,10 @@ yyreduce:
              }
     break;
 
-  case 51:
+  case 55:
 
 /* Line 1806 of yacc.c  */
-#line 556 "parser.y"
+#line 574 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
@@ -2487,10 +2533,10 @@ yyreduce:
              }
     break;
 
-  case 52:
+  case 56:
 
 /* Line 1806 of yacc.c  */
-#line 562 "parser.y"
+#line 580 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
@@ -2498,17 +2544,17 @@ yyreduce:
              }
     break;
 
-  case 53:
+  case 57:
 
 /* Line 1806 of yacc.c  */
-#line 567 "parser.y"
+#line 585 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
-  case 54:
+  case 58:
 
 /* Line 1806 of yacc.c  */
-#line 575 "parser.y"
+#line 593 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2521,10 +2567,10 @@ yyreduce:
              }
     break;
 
-  case 55:
+  case 59:
 
 /* Line 1806 of yacc.c  */
-#line 586 "parser.y"
+#line 604 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2534,10 +2580,10 @@ yyreduce:
              }
     break;
 
-  case 56:
+  case 60:
 
 /* Line 1806 of yacc.c  */
-#line 601 "parser.y"
+#line 619 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)));
@@ -2545,17 +2591,17 @@ yyreduce:
              }
     break;
 
-  case 57:
+  case 61:
 
 /* Line 1806 of yacc.c  */
-#line 609 "parser.y"
+#line 627 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
-  case 58:
+  case 62:
 
 /* Line 1806 of yacc.c  */
-#line 614 "parser.y"
+#line 632 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), get((yyvsp[(2) - (2)].plist)), NULL, scanner));
@@ -2564,10 +2610,10 @@ yyreduce:
              }
     break;
 
-  case 59:
+  case 63:
 
 /* Line 1806 of yacc.c  */
-#line 624 "parser.y"
+#line 642 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree keywordGuard((yyvsp[(1) - (3)].str));
@@ -2577,10 +2623,10 @@ yyreduce:
              }
     break;
 
-  case 60:
+  case 64:
 
 /* Line 1806 of yacc.c  */
-#line 638 "parser.y"
+#line 656 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2588,10 +2634,10 @@ yyreduce:
              }
     break;
 
-  case 61:
+  case 65:
 
 /* Line 1806 of yacc.c  */
-#line 646 "parser.y"
+#line 664 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2599,10 +2645,10 @@ yyreduce:
              }
     break;
 
-  case 62:
+  case 66:
 
 /* Line 1806 of yacc.c  */
-#line 654 "parser.y"
+#line 672 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2610,24 +2656,24 @@ yyreduce:
              }
     break;
 
-  case 63:
+  case 67:
 
 /* Line 1806 of yacc.c  */
-#line 667 "parser.y"
+#line 685 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (1)].plist); }
     break;
 
-  case 64:
+  case 68:
 
 /* Line 1806 of yacc.c  */
-#line 669 "parser.y"
+#line 687 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (2)].plist); }
     break;
 
-  case 65:
+  case 69:
 
 /* Line 1806 of yacc.c  */
-#line 674 "parser.y"
+#line 692 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.plist), SelectionParserParameter::createList());
@@ -2635,10 +2681,10 @@ yyreduce:
              }
     break;
 
-  case 66:
+  case 70:
 
 /* Line 1806 of yacc.c  */
-#line 680 "parser.y"
+#line 698 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserParameterListPointer list(get((yyvsp[(1) - (2)].plist)));
@@ -2648,10 +2694,10 @@ yyreduce:
              }
     break;
 
-  case 67:
+  case 71:
 
 /* Line 1806 of yacc.c  */
-#line 691 "parser.y"
+#line 709 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree nameGuard((yyvsp[(1) - (2)].str));
@@ -2660,24 +2706,24 @@ yyreduce:
              }
     break;
 
-  case 68:
+  case 72:
 
 /* Line 1806 of yacc.c  */
-#line 699 "parser.y"
+#line 717 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist);   }
     break;
 
-  case 69:
+  case 73:
 
 /* Line 1806 of yacc.c  */
-#line 700 "parser.y"
+#line 718 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist);   }
     break;
 
-  case 70:
+  case 74:
 
 /* Line 1806 of yacc.c  */
-#line 705 "parser.y"
+#line 723 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
@@ -2685,10 +2731,10 @@ yyreduce:
              }
     break;
 
-  case 71:
+  case 75:
 
 /* Line 1806 of yacc.c  */
-#line 711 "parser.y"
+#line 729 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2698,10 +2744,10 @@ yyreduce:
              }
     break;
 
-  case 72:
+  case 76:
 
 /* Line 1806 of yacc.c  */
-#line 719 "parser.y"
+#line 737 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2711,24 +2757,24 @@ yyreduce:
              }
     break;
 
-  case 73:
+  case 77:
 
 /* Line 1806 of yacc.c  */
-#line 729 "parser.y"
+#line 747 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist); }
     break;
 
-  case 74:
+  case 78:
 
 /* Line 1806 of yacc.c  */
-#line 730 "parser.y"
+#line 748 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist); }
     break;
 
-  case 75:
+  case 79:
 
 /* Line 1806 of yacc.c  */
-#line 735 "parser.y"
+#line 753 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[(1) - (1)].val))));
@@ -2736,10 +2782,10 @@ yyreduce:
              }
     break;
 
-  case 76:
+  case 80:
 
 /* Line 1806 of yacc.c  */
-#line 741 "parser.y"
+#line 759 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2749,10 +2795,10 @@ yyreduce:
              }
     break;
 
-  case 77:
+  case 81:
 
 /* Line 1806 of yacc.c  */
-#line 749 "parser.y"
+#line 767 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2762,10 +2808,10 @@ yyreduce:
              }
     break;
 
-  case 78:
+  case 82:
 
 /* Line 1806 of yacc.c  */
-#line 759 "parser.y"
+#line 777 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2773,10 +2819,10 @@ yyreduce:
              }
     break;
 
-  case 79:
+  case 83:
 
 /* Line 1806 of yacc.c  */
-#line 765 "parser.y"
+#line 783 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2784,10 +2830,10 @@ yyreduce:
              }
     break;
 
-  case 80:
+  case 84:
 
 /* Line 1806 of yacc.c  */
-#line 771 "parser.y"
+#line 789 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2795,10 +2841,10 @@ yyreduce:
              }
     break;
 
-  case 81:
+  case 85:
 
 /* Line 1806 of yacc.c  */
-#line 777 "parser.y"
+#line 795 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2806,17 +2852,17 @@ yyreduce:
              }
     break;
 
-  case 82:
+  case 86:
 
 /* Line 1806 of yacc.c  */
-#line 782 "parser.y"
+#line 800 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
-  case 83:
+  case 87:
 
 /* Line 1806 of yacc.c  */
-#line 787 "parser.y"
+#line 805 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createInteger((yyvsp[(1) - (1)].i)));
@@ -2824,10 +2870,10 @@ yyreduce:
              }
     break;
 
-  case 84:
+  case 88:
 
 /* Line 1806 of yacc.c  */
-#line 793 "parser.y"
+#line 811 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createReal((yyvsp[(1) - (1)].r)));
@@ -2835,10 +2881,10 @@ yyreduce:
              }
     break;
 
-  case 85:
+  case 89:
 
 /* Line 1806 of yacc.c  */
-#line 799 "parser.y"
+#line 817 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_ptr_sfree stringGuard((yyvsp[(1) - (1)].str));
@@ -2847,17 +2893,17 @@ yyreduce:
              }
     break;
 
-  case 86:
+  case 90:
 
 /* Line 1806 of yacc.c  */
-#line 805 "parser.y"
+#line 823 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
-  case 87:
+  case 91:
 
 /* Line 1806 of yacc.c  */
-#line 810 "parser.y"
+#line 828 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].i)));
@@ -2865,10 +2911,10 @@ yyreduce:
              }
     break;
 
-  case 88:
+  case 92:
 
 /* Line 1806 of yacc.c  */
-#line 816 "parser.y"
+#line 834 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].r)));
@@ -2876,10 +2922,10 @@ yyreduce:
              }
     break;
 
-  case 89:
+  case 93:
 
 /* Line 1806 of yacc.c  */
-#line 822 "parser.y"
+#line 840 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].r), (yyvsp[(3) - (3)].r)));
@@ -2890,7 +2936,7 @@ yyreduce:
 
 
 /* Line 1806 of yacc.c  */
-#line 2894 "parser.cpp"
+#line 2940 "parser.cpp"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
index 686f74259d8496df1264d02d086d8bda6259d2cd..2df34e28b72f665d06f55a8d444f15face03cb4c 100644 (file)
@@ -99,6 +99,8 @@ typedef union YYSTYPE
     char                       *str;
     struct gmx_ana_selmethod_t *meth;
 
+    gmx::SelectionStringMatchType                smt;
+
     gmx::SelectionTreeElementPointer            *sel;
     gmx::SelectionParserValue                   *val;
     gmx::SelectionParserValueListPointer        *vlist;
@@ -108,7 +110,7 @@ typedef union YYSTYPE
 
 
 /* Line 2068 of yacc.c  */
-#line 112 "parser.h"
+#line 114 "parser.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
index d90c81b451fd00f8ed408469825d174a9bd1fb08..962a573d20660d91f0410045ad3a64be6b897e3d 100644 (file)
@@ -75,6 +75,8 @@ using gmx::SelectionTreeElementPointer;
     char                       *str;
     struct gmx_ana_selmethod_t *meth;
 
+    gmx::SelectionStringMatchType                smt;
+
     gmx::SelectionTreeElementPointer            *sel;
     gmx::SelectionParserValue                   *val;
     gmx::SelectionParserValueListPointer        *vlist;
@@ -150,6 +152,7 @@ using gmx::SelectionTreeElementPointer;
 %type <r>     real_number number
 %type <str>   string
 %type <str>   pos_mod
+%type <smt>   str_match_type
 
 /* Expression non-terminals */
 %type <sel>   commands command cmd_plain
@@ -441,6 +444,13 @@ pos_mod:     EMPTY_POSMOD       { $$ = NULL; }
            | KEYWORD_POS        { $$ = $1;   }
 ;
 
+/* Matching mode forcing for keyword matching */
+str_match_type:
+             '~'                { $$ = gmx::eStringMatchType_RegularExpression; }
+           | '?'                { $$ = gmx::eStringMatchType_Wildcard; }
+           | '='                { $$ = gmx::eStringMatchType_Exact; }
+;
+
 /* Keyword selections */
 sel_expr:    pos_mod KEYWORD_GROUP
              {
@@ -454,7 +464,15 @@ sel_expr:    pos_mod KEYWORD_GROUP
              {
                  BEGIN_ACTION;
                  scoped_ptr_sfree posmodGuard($1);
-                 set($$, _gmx_sel_init_keyword($2, get($3), $1, scanner));
+                 set($$, _gmx_sel_init_keyword_strmatch($2, gmx::eStringMatchType_Auto, get($3), $1, scanner));
+                 CHECK_SEL($$);
+                 END_ACTION;
+             }
+           | pos_mod KEYWORD_STR str_match_type basic_value_list
+             {
+                 BEGIN_ACTION;
+                 scoped_ptr_sfree posmodGuard($1);
+                 set($$, _gmx_sel_init_keyword_strmatch($2, $3, get($4), $1, scanner));
                  CHECK_SEL($$);
                  END_ACTION;
              }
index 05ae205c5f7939f556e7cb1b9bf651c2a59f4027..68aebbc204ede19546dc99cef7414c5d71021edd 100644 (file)
@@ -253,6 +253,7 @@ using gmx::SelectionParserValueListPointer;
 using gmx::SelectionParserParameter;
 using gmx::SelectionParserParameterList;
 using gmx::SelectionParserParameterListPointer;
+using gmx::SelectionParserValue;
 using gmx::SelectionTreeElement;
 using gmx::SelectionTreeElementPointer;
 
@@ -636,8 +637,12 @@ _gmx_sel_init_comparison(const SelectionTreeElementPointer &left,
     return sel;
 }
 
-/*!
+/*! \brief
+ * Implementation method for keyword expression creation.
+ *
  * \param[in]  method Method to use.
+ * \param[in]  matchType String matching type (only used if \p method is
+ *      a string keyword and \p args is not empty.
  * \param[in]  args   Pointer to the first argument.
  * \param[in]  rpost  Reference position type to use (NULL = default).
  * \param[in]  scanner Scanner data structure.
@@ -646,8 +651,9 @@ _gmx_sel_init_comparison(const SelectionTreeElementPointer &left,
  * This function handles the creation of a gmx::SelectionTreeElement object for
  * selection methods that do not take parameters.
  */
-SelectionTreeElementPointer
-_gmx_sel_init_keyword(gmx_ana_selmethod_t *method,
+static SelectionTreeElementPointer
+init_keyword_internal(gmx_ana_selmethod_t *method,
+                      gmx::SelectionStringMatchType matchType,
                       SelectionParserValueListPointer args,
                       const char *rpost, yyscan_t scanner)
 {
@@ -685,6 +691,10 @@ _gmx_sel_init_keyword(gmx_ana_selmethod_t *method,
         /* Initialize the selection element */
         root.reset(new SelectionTreeElement(SEL_EXPRESSION));
         _gmx_selelem_set_method(root, kwmethod, scanner);
+        if (method->type == STR_VALUE)
+        {
+            _gmx_selelem_set_kwstr_match_type(root, matchType);
+        }
         SelectionParserParameterList params;
         params.push_back(
                 SelectionParserParameter::createFromExpression(NULL, child));
@@ -700,6 +710,49 @@ _gmx_sel_init_keyword(gmx_ana_selmethod_t *method,
     return root;
 }
 
+/*!
+ * \param[in]  method Method to use.
+ * \param[in]  args   Pointer to the first argument.
+ * \param[in]  rpost  Reference position type to use (NULL = default).
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a gmx::SelectionTreeElement object for
+ * selection methods that do not take parameters.
+ */
+SelectionTreeElementPointer
+_gmx_sel_init_keyword(gmx_ana_selmethod_t *method,
+                      SelectionParserValueListPointer args,
+                      const char *rpost, yyscan_t scanner)
+{
+    return init_keyword_internal(method, gmx::eStringMatchType_Auto, move(args),
+                                 rpost, scanner);
+}
+
+/*!
+ * \param[in]  method    Method to use.
+ * \param[in]  matchType String matching type.
+ * \param[in]  args      Pointer to the first argument.
+ * \param[in]  rpost     Reference position type to use (NULL = default).
+ * \param[in]  scanner   Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a gmx::SelectionTreeElement object for
+ * keyword string matching.
+ */
+SelectionTreeElementPointer
+_gmx_sel_init_keyword_strmatch(gmx_ana_selmethod_t *method,
+                               gmx::SelectionStringMatchType matchType,
+                               SelectionParserValueListPointer args,
+                               const char *rpost, yyscan_t scanner)
+{
+    GMX_RELEASE_ASSERT(method->type == STR_VALUE,
+            "String keyword method called for a non-string-valued method");
+    GMX_RELEASE_ASSERT(args && !args->empty(),
+            "String keyword matching method called without any values");
+    return init_keyword_internal(method, matchType, move(args), rpost, scanner);
+}
+
 /*!
  * \param[in]  method Method to use for initialization.
  * \param[in]  params Pointer to the first parameter.
index b1b73988b8e434c952b70d64d741686ab0088b14..fa78205dab66cdffe0802f7b47efa20b54a2e6f0 100644 (file)
@@ -67,6 +67,21 @@ struct gmx_ana_selparam_t;
 namespace gmx
 {
 
+//! \cond internal
+/*! \internal \brief
+ * String matching mode for string keyword expressions.
+ *
+ * \ingroup module_selection
+ */
+enum SelectionStringMatchType
+{
+    eStringMatchType_Auto,              //!< Deduce from the string.
+    eStringMatchType_Exact,             //!< Match as a literal string.
+    eStringMatchType_Wildcard,          //!< Match using ? and * as wildcards.
+    eStringMatchType_RegularExpression  //!< Match using regular expressions.
+};
+/*! \endcond */
+
 class SelectionParserValue;
 
 //! Container for a list of SelectionParserValue objects.
@@ -392,6 +407,12 @@ gmx::SelectionTreeElementPointer
 _gmx_sel_init_keyword(struct gmx_ana_selmethod_t *method,
                       gmx::SelectionParserValueListPointer args,
                       const char *rpost, void *scanner);
+/** Creates a gmx::SelectionTreeElement for string-matching keyword expression. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_keyword_strmatch(struct gmx_ana_selmethod_t *method,
+                               gmx::SelectionStringMatchType matchType,
+                               gmx::SelectionParserValueListPointer args,
+                               const char *rpost, void *scanner);
 /** Creates a gmx::SelectionTreeElement for a method expression from the parsed data. */
 gmx::SelectionTreeElementPointer
 _gmx_sel_init_method(struct gmx_ana_selmethod_t *method,
index 2255ba69894d3b1b75180fe9e887e63ec729c870..96cffea7ca4d25828cf9a0331e9fc2e495d67d55 100644 (file)
@@ -392,6 +392,11 @@ const char *const SyntaxHelpText::text[] = {
     "The match type is automatically guessed from the string: if it contains",
     "other characters than letters, numbers, '*', or '?', it is interpreted",
     "as a regular expression.",
+    "To force the matching to use literal string matching, use",
+    "[TT]name = \"C*\"[tt] to match a literal C*.",
+    "To force other type of matching, use '?' or '~' in place of '=' to force",
+    "wildcard or regular expression matching, respectively.[PAR]",
+
     "Strings that contain non-alphanumeric characters should be enclosed in",
     "double quotes as in the examples. For other strings, the quotes are",
     "optional, but if the value conflicts with a reserved keyword, a syntax",
index 67eca0e76ba73797ae36bec2704c47957cbc24ce..5f61e9e7d9163572f2c299bad2e429c41ed1a76b 100644 (file)
@@ -49,6 +49,8 @@
 #define USE_REGEX
 #endif
 
+#include <string>
+
 #include "gromacs/legacyheaders/macros.h"
 #include "gromacs/legacyheaders/smalloc.h"
 #include "gromacs/legacyheaders/string2.h"
@@ -56,6 +58,7 @@
 #include "gromacs/selection/selmethod.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/messagestringcollector.h"
+#include "gromacs/utility/stringutil.h"
 
 #include "keywords.h"
 #include "parsetree.h"
@@ -139,6 +142,8 @@ typedef struct t_methoddata_kwreal
  */
 typedef struct t_methoddata_kwstr
 {
+    /** Matching type for the strings. */
+    gmx::SelectionStringMatchType       matchType;
     /** Array of values for the keyword. */
     char             **v;
     /** Number of elements in the \p val array. */
@@ -156,7 +161,7 @@ typedef struct t_methoddata_kwstr
             regex_t    r;
 #endif
             /** The string if \p bRegExp is false; */
-            char      *s;
+            const char *s;
         }              u;
     }                 *m;
     /**< Array of strings/regular expressions to match against.*/
@@ -455,9 +460,30 @@ init_data_kwstr(int npar, gmx_ana_selparam_t *param)
     t_methoddata_kwstr *data;
 
     snew(data, 1);
+    data->matchType = gmx::eStringMatchType_Auto;
     return data;
 }
 
+/*!
+ * \param[in,out] sel   Selection element to initialize.
+ * \param[in]     matchType  Method to use to match string values.
+ *
+ * Sets the string matching method for string keyword matching.
+ */
+void
+_gmx_selelem_set_kwstr_match_type(const gmx::SelectionTreeElementPointer &sel,
+                                  gmx::SelectionStringMatchType matchType)
+{
+    t_methoddata_kwstr *d = (t_methoddata_kwstr *)sel->u.expr.mdata;
+
+    if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
+        || sel->u.expr.method->name != sm_keyword_str.name)
+    {
+        return;
+    }
+    d->matchType = matchType;
+}
+
 /*!
  * \param[in] top   Not used.
  * \param[in] npar  Not used (should be 2).
@@ -468,10 +494,7 @@ static void
 init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
-    char               *s;
     int                 i;
-    size_t              j;
-    bool                bRegExp;
 
     d->v   = param[0].val.u.s;
     d->n   = param[1].val.nr;
@@ -483,37 +506,34 @@ init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
     snew(d->m, d->n);
     for (i = 0; i < d->n; ++i)
     {
-        s = param[1].val.u.s[i];
-        bRegExp = false;
-        for (j = 0; j < strlen(s); ++j)
+        const char *s = param[1].val.u.s[i];
+        bool bRegExp = (d->matchType == gmx::eStringMatchType_RegularExpression);
+        if (d->matchType == gmx::eStringMatchType_Auto)
         {
-            if (ispunct(s[j]) && s[j] != '?' && s[j] != '*')
+            for (size_t j = 0; j < strlen(s); ++j)
             {
-                bRegExp = true;
-                break;
+                if (ispunct(s[j]) && s[j] != '?' && s[j] != '*')
+                {
+                    bRegExp = true;
+                    break;
+                }
             }
         }
         if (bRegExp)
         {
-            // TODO: Get rid of these prints to stderr
 #ifdef USE_REGEX
-            char               *buf;
-            snew(buf, strlen(s) + 3);
-            sprintf(buf, "^%s$", s);
-            if (regcomp(&d->m[i].u.r, buf, REG_EXTENDED | REG_NOSUB))
+            std::string buf(gmx::formatString("^%s$", s));
+            if (regcomp(&d->m[i].u.r, buf.c_str(), REG_EXTENDED | REG_NOSUB) != 0)
             {
-                bRegExp = false;
-                fprintf(stderr, "WARNING: error in regular expression,\n"
-                                "         will match '%s' as a simple string\n", s);
+                GMX_THROW(gmx::InvalidInputError(gmx::formatString(
+                                "Error in regular expression \"%s\"", s)));
             }
-            sfree(buf);
 #else
-            bRegExp = false;
-            fprintf(stderr, "WARNING: no regular expressions support,\n"
-                            "         will match '%s' as a simple string\n", s);
+            GMX_THROW(gmx::InvalidInputError(gmx::formatString(
+                            "No regular expression support, cannot match \"%s\"", s)));
 #endif
         }
-        if (!bRegExp)
+        else
         {
             d->m[i].u.s = s;
         }
@@ -574,18 +594,16 @@ evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
 #ifdef USE_REGEX
                 /* This branch should only be taken if regular expressions
                  * are available, but the ifdef is still needed. */
-                if (!regexec(&d->m[j].u.r, d->v[i], 0, NULL, 0))
-                {
-                    bFound = true;
-                }
+                bFound = (regexec(&d->m[j].u.r, d->v[i], 0, NULL, 0) == 0);
 #endif
             }
+            else if (d->matchType == gmx::eStringMatchType_Exact)
+            {
+                bFound = (strcmp(d->m[j].u.s, d->v[i]) == 0);
+            }
             else
             {
-                if (gmx_wcmatch(d->m[j].u.s, d->v[i]) == 0)
-                {
-                    bFound = true;
-                }
+                bFound = (gmx_wcmatch(d->m[j].u.s, d->v[i]) == 0);
             }
         }
         if (bFound)
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesForcedStringMatchingMode.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesForcedStringMatchingMode.xml
new file mode 100644 (file)
index 0000000..96aed6e
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">name = S1 "C?"</String>
+      <String Name="Name">name = S1 "C?"</String>
+      <String Name="Text">name = S1 "C?"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">name ? S1 "C?"</String>
+      <String Name="Name">name ? S1 "C?"</String>
+      <String Name="Text">name ? S1 "C?"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">5</Int>
+        <Int>1</Int>
+        <Int>4</Int>
+        <Int>7</Int>
+        <Int>10</Int>
+        <Int>13</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">10</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
index 8910a3b2967f6ce6dbf38978d1d14f08547b3f54..ce4d40c5e8518170372d227f0d82afd62ae10173 100644 (file)
@@ -8,6 +8,12 @@
       <String Name="Text">resname "R[BD]"</String>
       <Bool Name="Dynamic">false</Bool>
     </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">resname ~ "R[BD]"</String>
+      <String Name="Name">resname ~ "R[BD]"</String>
+      <String Name="Text">resname ~ "R[BD]"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
   </ParsedSelections>
   <CompiledSelections Name="Compiled">
     <Selection Name="Selection1">
         <Int>14</Int>
       </Sequence>
     </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">6</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
   </CompiledSelections>
 </ReferenceData>
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesWildcardMatching.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesWildcardMatching.xml
new file mode 100644 (file)
index 0000000..9c19c9f
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">name "S?"</String>
+      <String Name="Name">name "S?"</String>
+      <String Name="Text">name "S?"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+    <ParsedSelection Name="Selection2">
+      <String Name="Input">name ? "S?"</String>
+      <String Name="Name">name ? "S?"</String>
+      <String Name="Text">name ? "S?"</String>
+      <Bool Name="Dynamic">false</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">10</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+    <Selection Name="Selection2">
+      <Sequence Name="Atoms">
+        <Int Name="Length">10</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+</ReferenceData>
index 660af1e6335572d048bb3ce58a41d95f20174dc1..804dd51b8e5869082a8b8f1bd3eb61269095b651 100644 (file)
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_selection
  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <gtest/gtest.h>
 
 #include "gromacs/legacyheaders/smalloc.h"
@@ -362,6 +366,26 @@ TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
     EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
 }
 
+#ifdef HAVE_REGEX_H
+TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
+{
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    EXPECT_THROW({
+            sc_.parseFromString("resname ~ \"R[A\"");
+            sc_.compile();
+        }, gmx::InvalidInputError);
+}
+#else
+TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
+{
+    ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+    EXPECT_THROW({
+            sc_.parseFromString("resname \"R[AD]\"");
+            sc_.compile();
+        }, gmx::InvalidInputError);
+}
+#endif
+
 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
 {
     EXPECT_THROW(sc_.parseFromString("mindist from atomnr 1 cutoff"),
@@ -718,18 +742,40 @@ TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
     runTest("simple.gro", selections);
 }
 
+
+TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
+{
+    static const char * const selections[] = {
+        "name = S1 \"C?\"",
+        "name ? S1 \"C?\"",
+        NULL
+    };
+    runTest("simple.gro", selections);
+}
+
+
+TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
+{
+    static const char * const selections[] = {
+        "name \"S?\"",
+        "name ? \"S?\"",
+        NULL
+    };
+    runTest("simple.gro", selections);
+}
+
+
 #ifdef HAVE_REGEX_H
 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
-#else
-TEST_F(SelectionCollectionDataTest, DISABLED_HandlesRegexMatching)
-#endif
 {
     static const char * const selections[] = {
         "resname \"R[BD]\"",
+        "resname ~ \"R[BD]\"",
         NULL
     };
     runTest("simple.gro", selections);
 }
+#endif
 
 
 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)