C++ classes for selection parser values.
[alexxy/gromacs.git] / src / gromacs / selection / params.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements functions in selparam.h.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_selection
37  */
38 #include <algorithm>
39 #include <string>
40
41 #include "gromacs/legacyheaders/smalloc.h"
42 #include "gromacs/legacyheaders/string2.h"
43 #include "gromacs/legacyheaders/vec.h"
44
45 #include "gromacs/selection/position.h"
46 #include "gromacs/selection/selmethod.h"
47 #include "gromacs/selection/selparam.h"
48 #include "gromacs/utility/errorcodes.h"
49 #include "gromacs/utility/exceptions.h"
50 #include "gromacs/utility/gmxassert.h"
51 #include "gromacs/utility/messagestringcollector.h"
52 #include "gromacs/utility/stringutil.h"
53
54 #include "parsetree.h"
55 #include "position.h"
56 #include "scanner.h"
57 #include "selelem.h"
58
59 using gmx::SelectionParserValue;
60 using gmx::SelectionParserValueList;
61 using gmx::SelectionParserParameterPointer;
62 using gmx::SelectionParserParameterList;
63 using gmx::SelectionTreeElement;
64 using gmx::SelectionTreeElementPointer;
65
66 /*!
67  * \param[in] name   Name of the parameter to search.
68  * \param[in] nparam Number of parameters in the \p param array.
69  * \param[in] param  Parameter array to search.
70  * \returns   Pointer to the parameter in the \p param
71  *   or NULL if no parameter with name \p name was found.
72  *
73  * The comparison is case-sensitive.
74  */
75 gmx_ana_selparam_t *
76 gmx_ana_selparam_find(const char *name, int nparam, gmx_ana_selparam_t *param)
77 {
78     int                i;
79
80     if (nparam == 0)
81     {
82         return NULL;
83     }
84     /* Find the first non-null parameter */
85     i = 0;
86     while (i < nparam && param[i].name == NULL)
87     {
88         ++i;
89     }
90     /* Process the special case of a NULL parameter */
91     if (name == NULL)
92     {
93         return (i == 0) ? NULL : &param[i-1];
94     }
95     for ( ; i < nparam; ++i)
96     {
97         if (!strcmp(param[i].name, name))
98         {
99             return &param[i];
100         }
101         /* Check for 'no' prefix on boolean parameters */
102         if (param[i].val.type == NO_VALUE
103             && strlen(name) > 2 && name[0] == 'n' && name[1] == 'o'
104             && !strcmp(param[i].name, name+2))
105         {
106             return &param[i];
107         }
108     }
109     return NULL;
110 }
111
112 /*! \brief
113  * Does a type conversion on a SelectionParserValue.
114  *
115  * \param[in,out] value    Value to convert.
116  * \param[in]     type     Type to convert to.
117  * \param[in]     scanner  Scanner data structure.
118  * \returns       0 on success, a non-zero value on error.
119  */
120 static int
121 convert_value(SelectionParserValue *value, e_selvalue_t type, void *scanner)
122 {
123     if (value->type == type || type == NO_VALUE)
124     {
125         return 0;
126     }
127     if (value->hasExpressionValue())
128     {
129         /* Conversion from atom selection to position using default
130          * reference positions. */
131         if (value->type == GROUP_VALUE && type == POS_VALUE)
132         {
133             SelectionTreeElementPointer expr =
134                 _gmx_sel_init_position(value->expr, NULL, scanner);
135             // FIXME: Use exceptions
136             if (!expr)
137             {
138                 return -1;
139             }
140             *value = SelectionParserValue::createExpr(expr);
141             return 0;
142         }
143         return -1;
144     }
145     else
146     {
147         /* Integers to floating point are easy */
148         if (value->type == INT_VALUE && type == REAL_VALUE)
149         {
150             *value = SelectionParserValue::createRealRange(value->u.i.i1,
151                                                            value->u.i.i2);
152             return 0;
153         }
154         /* Reals that are integer-valued can also be converted */
155         if (value->type == REAL_VALUE && type == INT_VALUE)
156         {
157             int i1 = static_cast<int>(value->u.r.r1);
158             int i2 = static_cast<int>(value->u.r.r2);
159             if (gmx_within_tol(value->u.r.r1, i1, GMX_REAL_EPS)
160                 && gmx_within_tol(value->u.r.r2, i2, GMX_REAL_EPS))
161             {
162                 *value = SelectionParserValue::createIntegerRange(i1, i2);
163                 return 0;
164             }
165         }
166     }
167     return -1;
168 }
169
170 /*! \brief
171  * Does a type conversion on a list of values.
172  *
173  * \param[in,out] values   Values to convert.
174  * \param[in]     type     Type to convert to.
175  * \param[in]     scanner  Scanner data structure.
176  * \returns       0 on success, a non-zero value on error.
177  */
178 static int
179 convert_values(SelectionParserValueList *values, e_selvalue_t type, void *scanner)
180 {
181     int rc = 0;
182     SelectionParserValueList::iterator value;
183     for (value = values->begin(); value != values->end(); ++value)
184     {
185         int rc1 = convert_value(&*value, type, scanner);
186         if (rc1 != 0 && rc == 0)
187         {
188             rc = rc1;
189         }
190     }
191     /* FIXME: More informative error messages */
192     return rc;
193 }
194
195 /*! \brief
196  * Adds a child element for a parameter, keeping the parameter order.
197  *
198  * \param[in,out] root  Root element to which the child is added.
199  * \param[in]     child Child to add.
200  * \param[in]     param Parameter for which this child is a value.
201  *
202  * Puts \p child in the child list of \p root such that the list remains
203  * in the same order as the corresponding parameters.
204  */
205 static void
206 place_child(const SelectionTreeElementPointer &root,
207             const SelectionTreeElementPointer &child,
208             gmx_ana_selparam_t *param)
209 {
210     gmx_ana_selparam_t *ps;
211     int                 n;
212
213     ps = root->u.expr.method->param;
214     n  = param - ps;
215     /* Put the child element in the correct place */
216     if (!root->child || n < root->child->u.param - ps)
217     {
218         child->next = root->child;
219         root->child = child;
220     }
221     else
222     {
223         SelectionTreeElementPointer prev = root->child;
224         while (prev->next && prev->next->u.param - ps >= n)
225         {
226             prev = prev->next;
227         }
228         child->next = prev->next;
229         prev->next  = child;
230     }
231 }
232
233 /*! \brief
234  * Comparison function for sorting integer ranges.
235  * 
236  * \param[in] a Pointer to the first range.
237  * \param[in] b Pointer to the second range.
238  * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
239  *
240  * The ranges are primarily sorted based on their starting point, and
241  * secondarily based on length (longer ranges come first).
242  */
243 static int
244 cmp_int_range(const void *a, const void *b)
245 {
246     if (((int *)a)[0] < ((int *)b)[0])
247     {
248         return -1;
249     }
250     if (((int *)a)[0] > ((int *)b)[0])
251     {
252         return 1;
253     }
254     if (((int *)a)[1] > ((int *)b)[1])
255     {
256         return -1;
257     }
258     return 0;
259 }
260
261 /*! \brief
262  * Comparison function for sorting real ranges.
263  *
264  * \param[in] a Pointer to the first range.
265  * \param[in] b Pointer to the second range.
266  * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
267  *
268  * The ranges are primarily sorted based on their starting point, and
269  * secondarily based on length (longer ranges come first).
270  */
271 static int
272 cmp_real_range(const void *a, const void *b)
273 {
274     if (((real *)a)[0] < ((real *)b)[0])
275     {
276         return -1;
277     }
278     if (((real *)a)[0] > ((real *)b)[0])
279     {
280         return 1;
281     }
282     if (((real *)a)[1] > ((real *)b)[1])
283     {
284         return -1;
285     }
286     return 0;
287 }
288
289 /*! \brief
290  * Parses the values for a parameter that takes integer or real ranges.
291  * 
292  * \param[in] values List of values.
293  * \param     param  Parameter to parse.
294  * \param[in] scanner Scanner data structure.
295  * \returns   true if the values were parsed successfully, false otherwise.
296  */
297 static bool
298 parse_values_range(const SelectionParserValueList &values,
299                    gmx_ana_selparam_t *param, void *scanner)
300 {
301     int                *idata;
302     real               *rdata;
303     int                 i, j, n;
304
305     param->flags &= ~SPAR_DYNAMIC;
306     if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE)
307     {
308         GMX_ERROR_NORET(gmx::eeInternalError, "Invalid range parameter type");
309         return false;
310     }
311     idata = NULL;
312     rdata = NULL;
313     if (param->val.type == INT_VALUE)
314     {
315         snew(idata, values.size()*2);
316     }
317     else
318     {
319         snew(rdata, values.size()*2);
320     }
321     i = 0;
322     SelectionParserValueList::const_iterator value;
323     for (value = values.begin(); value != values.end(); ++value)
324     {
325         if (value->hasExpressionValue())
326         {
327             _gmx_selparser_error(scanner, "expressions not supported within range parameters");
328             return false;
329         }
330         if (value->type != param->val.type)
331         {
332             GMX_ERROR_NORET(gmx::eeInternalError, "Invalid range value type");
333             return false;
334         }
335         if (param->val.type == INT_VALUE)
336         {
337             int i1 = std::min(value->u.i.i1, value->u.i.i2);
338             int i2 = std::max(value->u.i.i1, value->u.i.i2);
339             /* Check if the new range overlaps or extends the previous one */
340             if (i > 0 && i1 <= idata[i-1]+1 && i2 >= idata[i-2]-1)
341             {
342                 idata[i-2] = std::min(idata[i-2], i1);
343                 idata[i-1] = std::max(idata[i-1], i2);
344             }
345             else
346             {
347                 idata[i++] = i1;
348                 idata[i++] = i2;
349             }
350         }
351         else
352         {
353             real r1 = std::min(value->u.r.r1, value->u.r.r2);
354             real r2 = std::max(value->u.r.r1, value->u.r.r2);
355             /* Check if the new range overlaps or extends the previous one */
356             if (i > 0 && r1 <= rdata[i-1] && r2 >= rdata[i-2])
357             {
358                 rdata[i-2] = std::min(rdata[i-2], r1);
359                 rdata[i-1] = std::max(rdata[i-1], r2);
360             }
361             else
362             {
363                 rdata[i++] = r1;
364                 rdata[i++] = r2;
365             }
366         }
367     }
368     n = i/2;
369     /* Sort the ranges and merge consequent ones */
370     if (param->val.type == INT_VALUE)
371     {
372         qsort(idata, n, 2*sizeof(int), &cmp_int_range);
373         for (i = j = 2; i < 2*n; i += 2)
374         {
375             if (idata[j-1]+1 >= idata[i])
376             {
377                 if (idata[i+1] > idata[j-1])
378                 {
379                     idata[j-1] = idata[i+1];
380                 }
381             }
382             else
383             {
384                 idata[j]   = idata[i];
385                 idata[j+1] = idata[i+1];
386                 j += 2;
387             }
388         }
389     }
390     else
391     {
392         qsort(rdata, n, 2*sizeof(real), &cmp_real_range);
393         for (i = j = 2; i < 2*n; i += 2)
394         {
395             if (rdata[j-1]+1 >= rdata[i])
396             {
397                 if (rdata[i+1] > rdata[j-1])
398                 {
399                     rdata[j-1] = rdata[i+1];
400                 }
401             }
402             else
403             {
404                 rdata[j]   = rdata[i];
405                 rdata[j+1] = rdata[i+1];
406                 j += 2;
407             }
408         }
409     }
410     n = j/2;
411     /* Store the values */
412     if (param->flags & SPAR_VARNUM)
413     {
414         param->val.nr  = n;
415         if (param->val.type == INT_VALUE)
416         {
417             srenew(idata, j);
418             _gmx_selvalue_setstore_alloc(&param->val, idata, j);
419         }
420         else
421         {
422             srenew(rdata, j);
423             _gmx_selvalue_setstore_alloc(&param->val, rdata, j);
424         }
425     }
426     else
427     {
428         if (n != param->val.nr)
429         {
430             _gmx_selparser_error(scanner, "the value should consist of exactly one range");
431             sfree(idata);
432             sfree(rdata);
433             return false;
434         }
435         if (param->val.type == INT_VALUE)
436         {
437             memcpy(param->val.u.i, idata, 2*n*sizeof(int));
438             sfree(idata);
439         }
440         else
441         {
442             memcpy(param->val.u.r, rdata, 2*n*sizeof(real));
443             sfree(rdata);
444         }
445     }
446     if (param->nvalptr)
447     {
448         *param->nvalptr = param->val.nr;
449     }
450     param->nvalptr = NULL;
451
452     return true;
453 }
454
455 /*! \brief
456  * Parses the values for a parameter that takes a variable number of values.
457  * 
458  * \param[in] values List of values.
459  * \param     param  Parameter to parse.
460  * \param     root   Selection element to which child expressions are added.
461  * \param[in] scanner Scanner data structure.
462  * \returns   true if the values were parsed successfully, false otherwise.
463  *
464  * For integer ranges, the sequence of numbers from the first to second value
465  * is stored, each as a separate value.
466  */
467 static bool
468 parse_values_varnum(const SelectionParserValueList &values,
469                     gmx_ana_selparam_t *param,
470                     const SelectionTreeElementPointer &root,
471                     void *scanner)
472 {
473     int                 i, j;
474
475     param->flags &= ~SPAR_DYNAMIC;
476     /* Compute number of values, considering also integer ranges. */
477     size_t valueCount = values.size();
478     if (param->val.type == INT_VALUE)
479     {
480         SelectionParserValueList::const_iterator value;
481         for (value = values.begin(); value != values.end(); ++value)
482         {
483             if (value->type == INT_VALUE && !value->hasExpressionValue())
484             {
485                 valueCount += abs(value->u.i.i2 - value->u.i.i1);
486             }
487         }
488     }
489
490     /* Check that the value type is actually implemented */
491     if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE
492         && param->val.type != STR_VALUE && param->val.type != POS_VALUE)
493     {
494         GMX_ERROR_NORET(gmx::eeInternalError,
495                         "Variable-count value type not implemented");
496         return false;
497     }
498
499     /* Reserve appropriate amount of memory */
500     if (param->val.type == POS_VALUE)
501     {
502         gmx_ana_pos_reserve(param->val.u.p, valueCount, 0);
503         gmx_ana_pos_set_nr(param->val.u.p, valueCount);
504         gmx_ana_indexmap_init(&param->val.u.p->m, NULL, NULL, INDEX_UNKNOWN);
505     }
506     else
507     {
508         _gmx_selvalue_reserve(&param->val, valueCount);
509     }
510
511     i     = 0;
512     SelectionParserValueList::const_iterator value;
513     for (value = values.begin(); value != values.end(); ++value)
514     {
515         if (value->hasExpressionValue())
516         {
517             _gmx_selparser_error(scanner, "expressions not supported within value lists");
518             return false;
519         }
520         if (value->type != param->val.type)
521         {
522             GMX_ERROR_NORET(gmx::eeInternalError, "Invalid value type");
523             return false;
524         }
525         switch (param->val.type)
526         {
527             case INT_VALUE:
528                 if (value->u.i.i1 <= value->u.i.i2)
529                 {
530                     for (j = value->u.i.i1; j <= value->u.i.i2; ++j)
531                     {
532                         param->val.u.i[i++] = j;
533                     }
534                 }
535                 else
536                 {
537                     for (j = value->u.i.i1; j >= value->u.i.i2; --j)
538                     {
539                         param->val.u.i[i++] = j;
540                     }
541                 }
542                 break;
543             case REAL_VALUE:
544                 if (value->u.r.r1 != value->u.r.r2)
545                 {
546                     _gmx_selparser_error(scanner, "real ranges not supported");
547                     return false;
548                 }
549                 param->val.u.r[i++] = value->u.r.r1;
550                 break;
551             case STR_VALUE:
552                 param->val.u.s[i++] = strdup(value->stringValue().c_str());
553                 break;
554             case POS_VALUE:  copy_rvec(value->u.x, param->val.u.p->x[i++]); break;
555             default: /* Should not be reached */
556                 GMX_ERROR_NORET(gmx::eeInternalError, "Invalid value type");
557                 return false;
558         }
559     }
560     param->val.nr = i;
561     if (param->nvalptr)
562     {
563         *param->nvalptr = param->val.nr;
564     }
565     param->nvalptr = NULL;
566     /* Create a dummy child element to store the string values.
567      * This element is responsible for freeing the values, but carries no
568      * other function. */
569     if (param->val.type == STR_VALUE)
570     {
571         SelectionTreeElementPointer child(new SelectionTreeElement(SEL_CONST));
572         _gmx_selelem_set_vtype(child, STR_VALUE);
573         child->setName(param->name);
574         child->flags &= ~SEL_ALLOCVAL;
575         child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA;
576         child->v.nr = param->val.nr;
577         _gmx_selvalue_setstore(&child->v, param->val.u.s);
578         /* Because the child is not group-valued, the u union is not used
579          * for anything, so we can abuse it by storing the parameter value
580          * as place_child() expects, but this is really ugly... */
581         child->u.param = param;
582         place_child(root, child, param);
583     }
584
585     return true;
586 }
587
588 /*! \brief
589  * Adds a new subexpression reference to a selection element.
590  *
591  * \param[in,out] root  Root element to which the subexpression is added.
592  * \param[in]     param Parameter for which this expression is a value.
593  * \param[in]     expr  Expression to add.
594  * \param[in]     scanner Scanner data structure.
595  * \returns       The created child element.
596  *
597  * Creates a new \ref SEL_SUBEXPRREF element and adds it into the child
598  * list of \p root.
599  * If \p expr is already a \ref SEL_SUBEXPRREF, it is used as it is.
600  * \ref SEL_ALLOCVAL is cleared for the returned element.
601  */
602 static SelectionTreeElementPointer
603 add_child(const SelectionTreeElementPointer &root, gmx_ana_selparam_t *param,
604           const SelectionTreeElementPointer &expr, void *scanner)
605 {
606     GMX_RELEASE_ASSERT(root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER,
607                        "Unsupported root element for selection parameter parser");
608     SelectionTreeElementPointer child;
609     /* Create a subexpression reference element if necessary */
610     if (expr->type == SEL_SUBEXPRREF)
611     {
612         child = expr;
613     }
614     else
615     {
616         child.reset(new SelectionTreeElement(SEL_SUBEXPRREF));
617         _gmx_selelem_set_vtype(child, expr->v.type);
618         child->child  = expr;
619     }
620     /* Setup the child element */
621     child->flags &= ~SEL_ALLOCVAL;
622     child->u.param = param;
623     if (child->v.type != param->val.type)
624     {
625         _gmx_selparser_error(scanner, "invalid expression value");
626         // FIXME: Use exceptions.
627         return SelectionTreeElementPointer();
628     }
629     _gmx_selelem_update_flags(child, scanner);
630     if ((child->flags & SEL_DYNAMIC) && !(param->flags & SPAR_DYNAMIC))
631     {
632         _gmx_selparser_error(scanner, "dynamic values not supported");
633         // FIXME: Use exceptions.
634         return SelectionTreeElementPointer();
635     }
636     if (!(child->flags & SEL_DYNAMIC))
637     {
638         param->flags &= ~SPAR_DYNAMIC;
639     }
640     /* Put the child element in the correct place */
641     place_child(root, child, param);
642     return child;
643 }
644
645 /*! \brief
646  * Parses an expression value for a parameter that takes a variable number of values.
647  * 
648  * \param[in] values List of values.
649  * \param     param  Parameter to parse.
650  * \param     root   Selection element to which child expressions are added.
651  * \param[in] scanner Scanner data structure.
652  * \returns   true if the values were parsed successfully, false otherwise.
653  */
654 static bool
655 parse_values_varnum_expr(const SelectionParserValueList &values,
656                          gmx_ana_selparam_t *param,
657                          const SelectionTreeElementPointer &root,
658                          void *scanner)
659 {
660     if (values.size() != 1 || !values.front().hasExpressionValue())
661     {
662         GMX_ERROR_NORET(gmx::eeInternalError, "Invalid expression value");
663         return false;
664     }
665
666     SelectionTreeElementPointer child
667         = add_child(root, param, values.front().expr, scanner);
668     if (!child)
669     {
670         return false;
671     }
672
673     /* Process single-valued expressions */
674     /* TODO: We should also handle SEL_SINGLEVAL expressions here */
675     if (child->v.type == POS_VALUE || child->v.type == GROUP_VALUE)
676     {
677         /* Set the value storage */
678         _gmx_selvalue_setstore(&child->v, param->val.u.ptr);
679         param->val.nr = 1;
680         if (param->nvalptr)
681         {
682             *param->nvalptr = param->val.nr;
683         }
684         param->nvalptr = NULL;
685         return true;
686     }
687
688     if (!(child->flags & SEL_VARNUMVAL))
689     {
690         _gmx_selparser_error(scanner, "invalid expression value");
691         return false;
692     }
693
694     child->flags   |= SEL_ALLOCVAL;
695     param->val.nr   = -1;
696     *param->nvalptr = param->val.nr;
697     /* Rest of the initialization is done during compilation in
698      * init_method(). */
699
700     return true;
701 }
702
703 /*! \brief
704  * Initializes the storage of an expression value.
705  *
706  * \param[in,out] sel   Selection element that evaluates the value.
707  * \param[in]     param Parameter to receive the value.
708  * \param[in]     i     The value of \p sel evaluates the value \p i for
709  *   \p param.
710  * \param[in]     scanner Scanner data structure.
711  *
712  * Initializes the data pointer of \p sel such that the result is stored
713  * as the value \p i of \p param.
714  * This function is used internally by parse_values_std().
715  */
716 static bool
717 set_expr_value_store(const SelectionTreeElementPointer &sel,
718                      gmx_ana_selparam_t *param, int i, void *scanner)
719 {
720     if (sel->v.type != GROUP_VALUE && !(sel->flags & SEL_SINGLEVAL))
721     {
722         _gmx_selparser_error(scanner, "invalid expression value");
723         return false;
724     }
725     switch (sel->v.type)
726     {
727         case INT_VALUE:   sel->v.u.i = &param->val.u.i[i]; break;
728         case REAL_VALUE:  sel->v.u.r = &param->val.u.r[i]; break;
729         case STR_VALUE:   sel->v.u.s = &param->val.u.s[i]; break;
730         case POS_VALUE:   sel->v.u.p = &param->val.u.p[i]; break;
731         case GROUP_VALUE: sel->v.u.g = &param->val.u.g[i]; break;
732         default: /* Error */
733             GMX_ERROR_NORET(gmx::eeInternalError, "Invalid value type");
734             return false;
735     }
736     sel->v.nr = 1;
737     sel->v.nalloc = -1;
738     return true;
739 }
740
741 /*! \brief
742  * Parses the values for a parameter that takes a constant number of values.
743  *
744  * \param[in] values List of values.
745  * \param     param  Parameter to parse.
746  * \param     root   Selection element to which child expressions are added.
747  * \param[in] scanner Scanner data structure.
748  * \returns   true if the values were parsed successfully, false otherwise.
749  *
750  * For integer ranges, the sequence of numbers from the first to second value
751  * is stored, each as a separate value.
752  */
753 static bool
754 parse_values_std(const SelectionParserValueList &values,
755                  gmx_ana_selparam_t *param,
756                  const SelectionTreeElementPointer &root, void *scanner)
757 {
758     int                i, j;
759     bool               bDynamic;
760
761     /* Handle atom-valued parameters */
762     if (param->flags & SPAR_ATOMVAL)
763     {
764         if (values.size() > 1)
765         {
766             _gmx_selparser_error(scanner, "more than one value not supported");
767             return false;
768         }
769         if (values.front().hasExpressionValue())
770         {
771             SelectionTreeElementPointer child
772                 = add_child(root, param, values.front().expr, scanner);
773             if (!child)
774             {
775                 return false;
776             }
777             child->flags |= SEL_ALLOCVAL;
778             if (child->v.type != GROUP_VALUE && (child->flags & SEL_ATOMVAL))
779             {
780                 /* Rest of the initialization is done during compilation in
781                  * init_method(). */
782                 /* TODO: Positions are not correctly handled */
783                 param->val.nr = -1;
784                 if (param->nvalptr)
785                 {
786                     *param->nvalptr = -1;
787                 }
788                 return true;
789             }
790             param->flags  &= ~SPAR_ATOMVAL;
791             param->val.nr  = 1;
792             if (param->nvalptr)
793             {
794                 *param->nvalptr = 1;
795             }
796             param->nvalptr = NULL;
797             if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
798                 || param->val.type == STR_VALUE)
799             {
800                 _gmx_selvalue_reserve(&param->val, 1);
801             }
802             return set_expr_value_store(child, param, 0, scanner);
803         }
804         /* If we reach here, proceed with normal parameter handling */
805         param->val.nr = 1;
806         if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
807             || param->val.type == STR_VALUE)
808         {
809             _gmx_selvalue_reserve(&param->val, 1);
810         }
811         param->flags &= ~SPAR_ATOMVAL;
812         param->flags &= ~SPAR_DYNAMIC;
813     }
814
815     i = 0;
816     bDynamic = false;
817     SelectionParserValueList::const_iterator value;
818     for (value = values.begin(); value != values.end() && i < param->val.nr; ++value)
819     {
820         if (value->type != param->val.type)
821         {
822             _gmx_selparser_error(scanner, "incorrect value skipped");
823             continue;
824         }
825         if (value->hasExpressionValue())
826         {
827             SelectionTreeElementPointer child
828                 = add_child(root, param, value->expr, scanner);
829             /* Check that the expression is valid */
830             if (!child)
831             {
832                 return false;
833             }
834             if (!set_expr_value_store(child, param, i, scanner))
835             {
836                 return false;
837             }
838             if (child->flags & SEL_DYNAMIC)
839             {
840                 bDynamic = true;
841             }
842         }
843         else
844         {
845             /* Value is not an expression */
846             switch (value->type)
847             {
848                 case INT_VALUE:
849                     if (value->u.i.i1 <= value->u.i.i2)
850                     {
851                         for (j = value->u.i.i1; j <= value->u.i.i2 && i < param->val.nr; ++j)
852                         {
853                             param->val.u.i[i++] = j;
854                         }
855                         if (j != value->u.i.i2 + 1)
856                         {
857                             _gmx_selparser_error(scanner, "extra values skipped");
858                         }
859                     }
860                     else
861                     {
862                         for (j = value->u.i.i1; j >= value->u.i.i2 && i < param->val.nr; --j)
863                         {
864                             param->val.u.i[i++] = j;
865                         }
866                         if (j != value->u.i.i2 - 1)
867                         {
868                             _gmx_selparser_error(scanner, "extra values skipped");
869                         }
870                     }
871                     --i;
872                     break;
873                 case REAL_VALUE:
874                     if (value->u.r.r1 != value->u.r.r2)
875                     {
876                         _gmx_selparser_error(scanner, "real ranges not supported");
877                         return false;
878                     }
879                     param->val.u.r[i] = value->u.r.r1;
880                     break;
881                 case STR_VALUE:
882                     param->val.u.s[i] = strdup(value->stringValue().c_str());
883                     break;
884                 case POS_VALUE:
885                     gmx_ana_pos_init_const(&param->val.u.p[i], value->u.x);
886                     break;
887                 case NO_VALUE:
888                 case GROUP_VALUE:
889                     GMX_ERROR_NORET(gmx::eeInternalError,
890                                     "Invalid non-expression value");
891                     return false;
892             }
893         }
894         ++i;
895     }
896     if (value != values.end())
897     {
898         _gmx_selparser_error(scanner, "extra values");
899         return false;
900     }
901     if (i < param->val.nr)
902     {
903         _gmx_selparser_error(scanner, "not enough values");
904         return false;
905     }
906     if (!bDynamic)
907     {
908         param->flags &= ~SPAR_DYNAMIC;
909     }
910     if (param->nvalptr)
911     {
912         *param->nvalptr = param->val.nr;
913     }
914     param->nvalptr = NULL;
915
916     return true;
917 }
918
919 /*! \brief
920  * Parses the values for a boolean parameter.
921  *
922  * \param[in] name   Name by which the parameter was given.
923  * \param[in] values List of values.
924  * \param     param  Parameter to parse.
925  * \param[in] scanner Scanner data structure.
926  * \returns   true if the values were parsed successfully, false otherwise.
927  */
928 static bool
929 parse_values_bool(const std::string &name,
930                   const SelectionParserValueList &values,
931                   gmx_ana_selparam_t *param, void *scanner)
932 {
933     bool bSetNo;
934
935     if (param->val.type != NO_VALUE)
936     {
937         GMX_ERROR_NORET(gmx::eeInternalError, "Invalid boolean parameter");
938         return false;
939     }
940     if (values.size() > 1 || (!values.empty() && values.front().type != INT_VALUE))
941     {
942         _gmx_selparser_error(scanner, "parameter takes only a yes/no/on/off/0/1 value");
943         return false;
944     }
945
946     bSetNo = false;
947     /* Check if the parameter name is given with a 'no' prefix */
948     if (name.length() > 2 && name[0] == 'n' && name[1] == 'o'
949         && name.compare(2, name.length() - 2, param->name) == 0)
950     {
951         bSetNo = true;
952     }
953     if (bSetNo && !values.empty())
954     {
955         _gmx_selparser_error(scanner, "parameter 'no%s' should not have a value",
956                              param->name);
957         return false;
958     }
959     if (!values.empty() && values.front().u.i.i1 == 0)
960     {
961         bSetNo = true;
962     }
963
964     *param->val.u.b = bSetNo ? false : true;
965     return true;
966 }
967
968 /*! \brief
969  * Parses the values for an enumeration parameter.
970  *
971  * \param[in] values List of values.
972  * \param     param  Parameter to parse.
973  * \param[in] scanner Scanner data structure.
974  * \returns   true if the values were parsed successfully, false otherwise.
975  */
976 static bool
977 parse_values_enum(const SelectionParserValueList &values,
978                   gmx_ana_selparam_t *param,
979                   void *scanner)
980 {
981     if (values.size() != 1)
982     {
983         _gmx_selparser_error(scanner, "a single value is required");
984         return false;
985     }
986     const SelectionParserValue &value = values.front();
987     if (value.type != STR_VALUE || param->val.type != STR_VALUE)
988     {
989         GMX_ERROR_NORET(gmx::eeInternalError, "Invalid enum parameter");
990         return false;
991     }
992     if (value.hasExpressionValue())
993     {
994         _gmx_selparser_error(scanner, "expression value for enumerated parameter not supported");
995         return false;
996     }
997
998     const std::string &svalue = value.stringValue();
999     int i = 1;
1000     int match = 0;
1001     while (param->val.u.s[i] != NULL)
1002     {
1003         if (gmx::startsWith(param->val.u.s[i], svalue))
1004         {
1005             /* Check if there is a duplicate match */
1006             if (match > 0)
1007             {
1008                 _gmx_selparser_error(scanner, "ambiguous value");
1009                 return false;
1010             }
1011             match = i;
1012         }
1013         ++i;
1014     }
1015     if (match == 0)
1016     {
1017         _gmx_selparser_error(scanner, "invalid value");
1018         return false;
1019     }
1020     param->val.u.s[0] = param->val.u.s[match];
1021     return true;
1022 }
1023
1024 /*! \brief
1025  * Replaces constant expressions with their values.
1026  *
1027  * \param[in,out] values First element in the value list to process.
1028  */
1029 static void
1030 convert_const_values(SelectionParserValueList *values)
1031 {
1032     SelectionParserValueList::iterator value;
1033     for (value = values->begin(); value != values->end(); ++value)
1034     {
1035         if (value->hasExpressionValue() && value->expr->v.type != GROUP_VALUE &&
1036             value->expr->type == SEL_CONST)
1037         {
1038             SelectionTreeElementPointer expr = value->expr;
1039             switch (expr->v.type)
1040             {
1041                 case INT_VALUE:
1042                     *value = SelectionParserValue::createInteger(expr->v.u.i[0]);
1043                     break;
1044                 case REAL_VALUE:
1045                     *value = SelectionParserValue::createReal(expr->v.u.r[0]);
1046                     break;
1047                 case STR_VALUE:
1048                     *value = SelectionParserValue::createString(expr->v.u.s[0]);
1049                     break;
1050                 case POS_VALUE:
1051                     *value = SelectionParserValue::createPosition(expr->v.u.p->x[0]);
1052                     break;
1053                 default:
1054                     GMX_ERROR_NORET(gmx::eeInternalError,
1055                                     "Unsupported value type");
1056                     break;
1057             }
1058         }
1059     }
1060 }
1061
1062 /*!
1063  * \param     pparams List of parameters from the selection parser.
1064  * \param[in] nparam  Number of parameters in \p params.
1065  * \param     params  Array of parameters to parse.
1066  * \param     root    Selection element to which child expressions are added.
1067  * \param[in] scanner Scanner data structure.
1068  * \returns   true if the parameters were parsed successfully, false otherwise.
1069  *
1070  * Initializes the \p params array based on the parameters in \p pparams.
1071  * See the documentation of \c gmx_ana_selparam_t for different options
1072  * available for parsing.
1073  *
1074  * The list \p pparams and any associated values are freed after the parameters
1075  * have been processed, no matter is there was an error or not.
1076  */
1077 bool
1078 _gmx_sel_parse_params(const SelectionParserParameterList &pparams,
1079                       int nparam, gmx_ana_selparam_t *params,
1080                       const SelectionTreeElementPointer &root, void *scanner)
1081 {
1082     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
1083     gmx_ana_selparam_t *oparam;
1084     bool                bOk, rc;
1085     int                 i;
1086
1087     /* Check that the value pointers of SPAR_VARNUM parameters are NULL and
1088      * that they are not NULL for other parameters */
1089     bOk = true;
1090     for (i = 0; i < nparam; ++i)
1091     {
1092         std::string contextStr = gmx::formatString("In parameter '%s'", params[i].name);
1093         gmx::MessageStringContext  context(errors, contextStr);
1094         if (params[i].val.type != POS_VALUE && (params[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
1095         {
1096             if (params[i].val.u.ptr != NULL)
1097             {
1098                 _gmx_selparser_error(scanner, "value pointer is not NULL "
1099                                      "although it should be for SPAR_VARNUM "
1100                                      "and SPAR_ATOMVAL parameters");
1101             }
1102             if ((params[i].flags & SPAR_VARNUM)
1103                 && (params[i].flags & SPAR_DYNAMIC) && !params[i].nvalptr)
1104             {
1105                 _gmx_selparser_error(scanner, "nvalptr is NULL but both "
1106                                      "SPAR_VARNUM and SPAR_DYNAMIC are specified");
1107                 bOk = false;
1108             }
1109         }
1110         else
1111         {
1112             if (params[i].val.u.ptr == NULL)
1113             {
1114                 _gmx_selparser_error(scanner, "value pointer is NULL");
1115                 bOk = false;
1116             }
1117         }
1118     }
1119     if (!bOk)
1120     {
1121         return false;
1122     }
1123     /* Parse the parameters */
1124     i = 0;
1125     SelectionParserParameterList::const_iterator piter;
1126     for (piter = pparams.begin(); piter != pparams.end(); ++piter)
1127     {
1128         const SelectionParserParameterPointer &pparam = *piter;
1129         std::string contextStr;
1130         /* Find the parameter and make some checks */
1131         if (!pparam->name().empty())
1132         {
1133             contextStr = gmx::formatString("In parameter '%s'", pparam->name().c_str());
1134             i = -1;
1135             oparam = gmx_ana_selparam_find(pparam->name().c_str(), nparam, params);
1136         }
1137         else if (i >= 0)
1138         {
1139             contextStr = gmx::formatString("In value %d", i + 1);
1140             oparam = &params[i];
1141             if (oparam->name != NULL)
1142             {
1143                 oparam = NULL;
1144                 _gmx_selparser_error(scanner, "too many NULL parameters provided");
1145                 bOk = false;
1146                 continue;
1147             }
1148             ++i;
1149         }
1150         else
1151         {
1152             _gmx_selparser_error(scanner, "all NULL parameters should appear in the beginning of the list");
1153             bOk = false;
1154             continue;
1155         }
1156         gmx::MessageStringContext  context(errors, contextStr);
1157         if (!oparam)
1158         {
1159             _gmx_selparser_error(scanner, "unknown parameter skipped");
1160             bOk = false;
1161             continue;
1162         }
1163         if (oparam->val.type != NO_VALUE && pparam->values().empty())
1164         {
1165             _gmx_selparser_error(scanner, "no value provided");
1166             bOk = false;
1167             continue;
1168         }
1169         if (oparam->flags & SPAR_SET)
1170         {
1171             _gmx_selparser_error(scanner, "parameter set multiple times, extra values skipped");
1172             bOk = false;
1173             continue;
1174         }
1175         oparam->flags |= SPAR_SET;
1176         /* Process the values for the parameter */
1177         convert_const_values(pparam->values_.get());
1178         if (convert_values(pparam->values_.get(), oparam->val.type, scanner) != 0)
1179         {
1180             _gmx_selparser_error(scanner, "invalid value");
1181             bOk = false;
1182             continue;
1183         }
1184         if (oparam->val.type == NO_VALUE)
1185         {
1186             rc = parse_values_bool(pparam->name(), pparam->values(), oparam, scanner);
1187         }
1188         else if (oparam->flags & SPAR_RANGES)
1189         {
1190             rc = parse_values_range(pparam->values(), oparam, scanner);
1191         }
1192         else if (oparam->flags & SPAR_VARNUM)
1193         {
1194             if (pparam->values().size() == 1
1195                 && pparam->values().front().hasExpressionValue())
1196             {
1197                 rc = parse_values_varnum_expr(pparam->values(), oparam, root, scanner);
1198             }
1199             else
1200             {
1201                 rc = parse_values_varnum(pparam->values(), oparam, root, scanner);
1202             }
1203         }
1204         else if (oparam->flags & SPAR_ENUMVAL)
1205         {
1206             rc = parse_values_enum(pparam->values(), oparam, scanner);
1207         }
1208         else
1209         {
1210             rc = parse_values_std(pparam->values(), oparam, root, scanner);
1211         }
1212         if (!rc)
1213         {
1214             bOk = false;
1215         }
1216     }
1217     /* Check that all required parameters are present */
1218     for (i = 0; i < nparam; ++i)
1219     {
1220         if (!(params[i].flags & SPAR_OPTIONAL) && !(params[i].flags & SPAR_SET))
1221         {
1222             _gmx_selparser_error(scanner, "required parameter '%s' not specified", params[i].name);
1223             bOk = false;
1224         }
1225     }
1226
1227     return bOk;
1228 }