2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2009-2018, The GROMACS development team.
5 * Copyright (c) 2019,2021, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 * Handling of intermediate selection parser data.
40 * The data types declared in this header are used by the parser to store
41 * intermediate data when constructing method expressions.
42 * In particular, the parameters for the method are stored.
43 * The intermediate data is freed once a gmx::SelectionTreeElement object can
46 * This is an implementation header: there should be no need to use it outside
49 * \author Teemu Murtola <teemu.murtola@gmail.com>
50 * \ingroup module_selection
52 #ifndef GMX_SELECTION_PARSETREE_H
53 #define GMX_SELECTION_PARSETREE_H
60 #include "gromacs/math/vec.h"
61 #include "gromacs/math/vectypes.h"
62 #include "gromacs/utility/gmxassert.h"
63 #include "gromacs/utility/real.h"
68 struct gmx_ana_indexgrps_t;
69 struct gmx_ana_selmethod_t;
70 struct gmx_ana_selparam_t;
77 * String matching mode for string keyword expressions.
79 * \ingroup module_selection
81 enum SelectionStringMatchType
83 eStringMatchType_Auto, //!< Deduce from the string.
84 eStringMatchType_Exact, //!< Match as a literal string.
85 eStringMatchType_Wildcard, //!< Match using ? and * as wildcards.
86 eStringMatchType_RegularExpression //!< Match using regular expressions.
90 class SelectionParserValue;
92 //! Container for a list of SelectionParserValue objects.
93 typedef std::list<SelectionParserValue> SelectionParserValueList;
94 //! Smart pointer type for managing a SelectionParserValueList.
95 typedef std::unique_ptr<SelectionParserValueList> SelectionParserValueListPointer;
99 * Describes a parsed value, possibly resulting from expression evaluation.
101 * All factory methods and the constructors may throw an std::bad_alloc if
104 * \ingroup module_selection
106 class SelectionParserValue
109 //! Allocates and initializes an empty value list.
110 static SelectionParserValueListPointer createList()
112 return std::make_unique<SelectionParserValueList>();
115 * Allocates and initializes a value list with a single value.
117 * \param[in] value Initial value to put in the list.
118 * \returns Pointer to a new value list that contains \p value.
120 static SelectionParserValueListPointer createList(const SelectionParserValue& value)
122 SelectionParserValueListPointer list(new SelectionParserValueList);
123 list->push_back(value);
127 * Allocates and initializes an expression value.
129 * \param[in] expr Root of the expression tree to assign to the value.
130 * \returns The newly created value.
132 static SelectionParserValue createExpr(const gmx::SelectionTreeElementPointer& expr)
134 return SelectionParserValue(expr);
137 * Allocates and initializes a constant integer value.
139 * \param[in] value Integer value to assign to the value.
140 * \param[in] location Location of the value.
141 * \returns The newly created value.
143 static SelectionParserValue createInteger(int value, const SelectionLocation& location)
145 SelectionParserValue result(INT_VALUE, location);
146 result.u.i.i1 = result.u.i.i2 = value;
150 * Allocates and initializes a constant integer range value.
152 * \param[in] from Beginning of the range to assign to the value.
153 * \param[in] to End of the range to assign to the value.
154 * \param[in] location Location of the value.
155 * \returns The newly created value.
157 static SelectionParserValue createIntegerRange(int from, int to, const SelectionLocation& location)
159 SelectionParserValue result(INT_VALUE, location);
160 result.u.i.i1 = from;
165 * Allocates and initializes a constant floating-point value.
167 * \param[in] value Floating-point value to assign to the value.
168 * \param[in] location Location of the value.
169 * \returns The newly created value.
171 static SelectionParserValue createReal(real value, const SelectionLocation& location)
173 SelectionParserValue result(REAL_VALUE, location);
174 result.u.r.r1 = result.u.r.r2 = value;
178 * Allocates and initializes a constant floating-point range value.
180 * \param[in] from Beginning of the range to assign to the value.
181 * \param[in] to End of the range to assign to the value.
182 * \param[in] location Location of the value.
183 * \returns The newly created value.
185 static SelectionParserValue createRealRange(real from, real to, const SelectionLocation& location)
187 SelectionParserValue result(REAL_VALUE, location);
188 result.u.r.r1 = from;
193 * Allocates and initializes a constant string value.
195 * \param[in] value String to assign to the value.
196 * \param[in] location Location of the value.
197 * \returns The newly created value.
199 static SelectionParserValue createString(const char* value, const SelectionLocation& location)
201 SelectionParserValue result(STR_VALUE, location);
206 * Allocates and initializes a constant position value.
208 * \param[in] value Position vector to assign to the value.
209 * \param[in] location Location of the value.
210 * \returns The newly created value.
212 static SelectionParserValue createPosition(rvec value, const SelectionLocation& location)
214 SelectionParserValue result(POS_VALUE, location);
215 copy_rvec(value, result.u.x);
219 //! Returns the location of this value in the parsed selection text.
220 const SelectionLocation& location() const { return location_; }
221 //! Returns true if the value comes from expression evaluation.
222 bool hasExpressionValue() const { return static_cast<bool>(expr); }
224 //! Returns the string value (\a type must be ::STR_VALUE).
225 const std::string& stringValue() const
227 GMX_ASSERT(type == STR_VALUE && !hasExpressionValue(),
228 "Attempted to retrieve string value from a non-string value");
232 // TODO: boost::any or similar could be nicer for the implementation.
233 //! Type of the value.
235 //! Expression pointer if the value is the result of an expression.
236 gmx::SelectionTreeElementPointer expr;
237 //! String value for \a type ::STR_VALUE.
239 //! The actual value if \a expr is NULL and \a type is not ::STR_VALUE.
242 //! The integer value/range (\a type ::INT_VALUE).
245 //! Beginning of the range.
247 //! End of the range; equals \a i1 for a single integer.
250 //! The real value/range (\a type ::REAL_VALUE).
253 //! Beginning of the range.
255 //! End of the range; equals \a r1 for a single number.
258 //! The position value (\a type ::POS_VALUE).
264 * Initializes a new value.
266 * \param[in] type Type for the new value.
267 * \param[in] location Location for the value.
269 SelectionParserValue(e_selvalue_t type, const SelectionLocation& location);
271 * Initializes a new expression value.
273 * \param[in] expr Expression for the value.
275 explicit SelectionParserValue(const gmx::SelectionTreeElementPointer& expr);
277 //! Location of the value in the parsed text.
278 SelectionLocation location_;
281 class SelectionParserParameter;
283 //! Container for a list of SelectionParserParameter objects.
284 typedef std::list<SelectionParserParameter> SelectionParserParameterList;
285 //! Smart pointer type for managing a SelectionParserParameterList.
286 typedef std::unique_ptr<SelectionParserParameterList> SelectionParserParameterListPointer;
289 * Describes a parsed method parameter.
291 * \ingroup module_selection
293 class SelectionParserParameter
296 // Default move constructor and assignment. Only needed for old compilers.
298 SelectionParserParameter(SelectionParserParameter&& o) noexcept :
299 name_(std::move(o.name_)), location_(o.location_), values_(std::move(o.values_))
303 SelectionParserParameter& operator=(SelectionParserParameter&& o) noexcept
305 name_ = std::move(o.name_);
306 location_ = o.location_;
307 values_ = std::move(o.values_);
312 //! Allocates and initializes an empty parameter list.
313 static SelectionParserParameterListPointer createList()
315 return std::make_unique<SelectionParserParameterList>();
318 * Allocates and initializes a parsed method parameter.
320 * \param[in] name Name for the new parameter (can be NULL).
321 * \param[in] values List of values for the parameter.
322 * \param[in] location Location of the parameter.
323 * \returns Pointer to the newly allocated parameter.
324 * \throws std::bad_alloc if out of memory.
326 static SelectionParserParameter create(const char* name,
327 SelectionParserValueListPointer values,
328 const SelectionLocation& location)
330 return SelectionParserParameter(name, std::move(values), location);
332 //! \copydoc create(const char *, SelectionParserValueListPointer, const SelectionLocation &)
333 static SelectionParserParameter create(const std::string& name,
334 SelectionParserValueListPointer values,
335 const SelectionLocation& location)
337 return SelectionParserParameter(name.c_str(), std::move(values), location);
340 * Allocates and initializes a parsed method parameter.
342 * \param[in] name Name for the new parameter (can be NULL).
343 * \param[in] value Value for the parameter.
344 * \param[in] location Location of the parameter.
345 * \returns Pointer to the newly allocated parameter.
346 * \throws std::bad_alloc if out of memory.
348 * This overload is a convenience wrapper for the case when creating
349 * parameters outside the actual Bison parser and only a single value
352 static SelectionParserParameter create(const char* name,
353 const SelectionParserValue& value,
354 const SelectionLocation& location)
356 return create(name, SelectionParserValue::createList(value), location);
359 * Allocates and initializes a parsed method parameter.
361 * \param[in] name Name for the new parameter (can be NULL).
362 * \param[in] expr Expression value for the parameter.
363 * \returns Pointer to the newly allocated parameter.
364 * \throws std::bad_alloc if out of memory.
366 * This overload is a convenience wrapper for the case when creating
367 * parameters outside the actual Bison parser and only a single
368 * expression value is necessary.
370 static SelectionParserParameter createFromExpression(const char* name,
371 const SelectionTreeElementPointer& expr)
373 return create(name, SelectionParserValue::createExpr(expr), expr->location());
375 //! \copydoc createFromExpression(const char *, const SelectionTreeElementPointer &)
376 static SelectionParserParameter createFromExpression(const std::string& name,
377 const SelectionTreeElementPointer& expr)
379 return create(name.c_str(), SelectionParserValue::createExpr(expr), expr->location());
382 //! Returns the name of the parameter (may be empty).
383 const std::string& name() const { return name_; }
384 //! Returns the location of this parameter in the parsed selection text.
385 const SelectionLocation& location() const { return location_; }
386 //! Returns the values for the parameter.
387 const SelectionParserValueList& values() const { return *values_; }
391 * Initializes a parsed method parameter.
393 * \param[in] name Name for the new parameter (can be NULL).
394 * \param[in] values List of values for the parameter.
395 * \param[in] location Location of the parameter.
396 * \throws std::bad_alloc if out of memory.
398 SelectionParserParameter(const char* name,
399 SelectionParserValueListPointer values,
400 const SelectionLocation& location);
402 //! Name of the parameter.
404 //! Location of the parameter in the parsed text.
405 SelectionLocation location_;
407 // TODO: Make private, there is only one direct user.
409 //! Values for this parameter.
410 SelectionParserValueListPointer values_;
416 * Handles exceptions caught within the Bison code.
418 * \retval `true` if the parser should attempt error recovery.
419 * \retval `false` if the parser should immediately abort.
421 * This function is called whenever an exception is caught within Bison
422 * actions. Since exceptions cannot propagate through Bison code, the
423 * exception is saved (potentially with some extra context information) so that
424 * the caller of the parser can rethrow the exception.
426 * If it is possible to recover from the exception, then the function returns
427 * `true`, and Bison enters error recovery state. At the end of the recovery,
428 * _gmx_selparser_handle_error() is called.
429 * If this function returns false, then Bison immediately aborts the parsing
430 * so that the caller can rethrow the exception.
432 bool _gmx_selparser_handle_exception(void* scanner, std::exception* ex);
434 * Handles errors in the selection parser.
436 * \returns `true` if parsing can continue with the next selection.
437 * \throws std::bad_alloc if out of memory during the error processing.
438 * \throws unspecified Can throw the stored exception if recovery from that
439 * exception is not possible.
441 * This function is called during error recovery, after Bison has discarded all
442 * the symbols for the erroneous selection.
443 * At this point, the full selection that caused the error is known, and can be
444 * added to the error context.
446 * For an interactive parser, this function returns `true` to let the parsing
447 * continue with the next selection, or to let the user enter the next
448 * selection, if it was possible to recover from the exception.
449 * For other cases, this will either rethrow the original exception with added
450 * context, or return `false` after adding the context to the error reporter.
451 * Any exceptions thrown from this method are again caught by Bison and result
452 * in termination of the parsing; the caller can then rethrow them.
454 bool _gmx_selparser_handle_error(void* scanner);
456 /** Propagates the flags for selection elements. */
457 void _gmx_selelem_update_flags(const gmx::SelectionTreeElementPointer& sel);
459 /** Initializes the method parameter data of \ref SEL_EXPRESSION and
460 * \ref SEL_MODIFIER elements. */
461 void _gmx_selelem_init_method_params(const gmx::SelectionTreeElementPointer& sel, void* scanner);
462 /** Initializes the method for a \ref SEL_EXPRESSION selection element. */
463 void _gmx_selelem_set_method(const gmx::SelectionTreeElementPointer& sel,
464 struct gmx_ana_selmethod_t* method,
467 /* An opaque pointer. */
468 #ifndef YY_TYPEDEF_YY_SCANNER_T
469 # define YY_TYPEDEF_YY_SCANNER_T
470 typedef void* yyscan_t;
472 /** \brief Creates a gmx::SelectionTreeElement for arithmetic expression evaluation.
474 * \param[in] left Selection element for the left hand side.
475 * \param[in] right Selection element for the right hand side.
476 * \param[in] op String representation of the operator.
477 * \param[in] scanner Scanner data structure.
478 * \returns The created selection element.
480 * This function handles the creation of a gmx::SelectionTreeElement object for
481 * arithmetic expressions.
483 gmx::SelectionTreeElementPointer _gmx_sel_init_arithmetic(const gmx::SelectionTreeElementPointer& left,
484 const gmx::SelectionTreeElementPointer& right,
487 /** Creates a gmx::SelectionTreeElement for comparsion expression evaluation. */
488 gmx::SelectionTreeElementPointer _gmx_sel_init_comparison(const gmx::SelectionTreeElementPointer& left,
489 const gmx::SelectionTreeElementPointer& right,
492 /** Creates a gmx::SelectionTreeElement for a keyword expression from the parsed data. */
493 gmx::SelectionTreeElementPointer _gmx_sel_init_keyword(struct gmx_ana_selmethod_t* method,
494 gmx::SelectionParserValueListPointer args,
497 /** Creates a gmx::SelectionTreeElement for string-matching keyword expression. */
498 gmx::SelectionTreeElementPointer _gmx_sel_init_keyword_strmatch(struct gmx_ana_selmethod_t* method,
499 gmx::SelectionStringMatchType matchType,
500 gmx::SelectionParserValueListPointer args,
503 /** Creates a gmx::SelectionTreeElement for "keyword of" expression. */
504 gmx::SelectionTreeElementPointer _gmx_sel_init_keyword_of(struct gmx_ana_selmethod_t* method,
505 const gmx::SelectionTreeElementPointer& group,
508 /** Creates a gmx::SelectionTreeElement for a method expression from the parsed data. */
509 gmx::SelectionTreeElementPointer _gmx_sel_init_method(struct gmx_ana_selmethod_t* method,
510 gmx::SelectionParserParameterListPointer params,
513 /** Creates a gmx::SelectionTreeElement for a modifier expression from the parsed data. */
514 gmx::SelectionTreeElementPointer _gmx_sel_init_modifier(struct gmx_ana_selmethod_t* mod,
515 gmx::SelectionParserParameterListPointer params,
516 const gmx::SelectionTreeElementPointer& sel,
518 /** Creates a gmx::SelectionTreeElement for evaluation of reference positions. */
519 gmx::SelectionTreeElementPointer _gmx_sel_init_position(const gmx::SelectionTreeElementPointer& expr,
523 /** Creates a gmx::SelectionTreeElement for a constant position. */
524 gmx::SelectionTreeElementPointer _gmx_sel_init_const_position(real x, real y, real z, void* scanner);
525 /** Creates a gmx::SelectionTreeElement for a index group expression using group name. */
526 gmx::SelectionTreeElementPointer _gmx_sel_init_group_by_name(const char* name, void* scanner);
527 /** Creates a gmx::SelectionTreeElement for a index group expression using group index. */
528 gmx::SelectionTreeElementPointer _gmx_sel_init_group_by_id(int id, void* scanner);
529 /** Creates a gmx::SelectionTreeElement for a variable reference */
530 gmx::SelectionTreeElementPointer _gmx_sel_init_variable_ref(const gmx::SelectionTreeElementPointer& sel,
533 /** Creates a root gmx::SelectionTreeElement for a selection. */
534 gmx::SelectionTreeElementPointer _gmx_sel_init_selection(const char* name,
535 const gmx::SelectionTreeElementPointer& sel,
537 /** Creates a root gmx::SelectionTreeElement elements for a variable assignment. */
538 gmx::SelectionTreeElementPointer _gmx_sel_assign_variable(const char* name,
539 const gmx::SelectionTreeElementPointer& expr,
541 /** Appends a root gmx::SelectionTreeElement to a selection collection. */
542 gmx::SelectionTreeElementPointer _gmx_sel_append_selection(const gmx::SelectionTreeElementPointer& sel,
543 gmx::SelectionTreeElementPointer last,
545 /** Check whether the parser should finish. */
546 bool _gmx_sel_parser_should_finish(void* scanner);
549 /** Initializes an array of parameters based on input from the selection parser. */
550 void _gmx_sel_parse_params(const gmx::SelectionParserParameterList& params,
552 struct gmx_ana_selparam_t* param,
553 const gmx::SelectionTreeElementPointer& root,