/*! * \param[in,out] sel Selection element to initialize. * \param[in] method Selection method to set. * \param[in] scanner Scanner data structure. * * Makes a copy of \p method and stores it in \p sel->u.expr.method, * and calls _gmx_selelem_init_method_params(); */ void _gmx_selelem_set_method(const gmx::SelectionTreeElementPointer &sel, gmx_ana_selmethod_t *method, yyscan_t scanner) { _gmx_selelem_set_vtype(sel, method->type); sel->setName(method->name); snew(sel->u.expr.method, 1); memcpy(sel->u.expr.method, method, sizeof(gmx_ana_selmethod_t)); _gmx_selelem_init_method_params(sel, scanner); }
/*! * \param sel Selection to append (can be NULL, in which * case nothing is done). * \param last Last selection, or NULL if not present or not known. * \param scanner Scanner data structure. * \returns The last selection after the append. * * Appends \p sel after the last root element, and returns either \p sel * (if it was non-NULL) or the last element (if \p sel was NULL). */ SelectionTreeElementPointer _gmx_sel_append_selection(const gmx::SelectionTreeElementPointer &sel, gmx::SelectionTreeElementPointer last, yyscan_t scanner) { gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner); /* Append sel after last, or the last element of sc if last is NULL */ if (last) { last->next = sel; } else { if (sc->root) { last = sc->root; while (last->next) { last = last->next; } last->next = sel; } else { sc->root = sel; } } /* Initialize a selection object if necessary */ if (sel) { last = sel; /* Add the new selection to the collection if it is not a variable. */ if (sel->child->type != SEL_SUBEXPR) { gmx::SelectionDataPointer selPtr( new gmx::internal::SelectionData( sel.get(), _gmx_sel_lexer_pselstr(scanner))); sc->sel.push_back(gmx::move(selPtr)); } } /* Clear the selection string now that we've saved it */ _gmx_sel_lexer_clear_pselstr(scanner); return last; }
/*! * \param[in,out] sel Value of the variable. * \returns The created selection element that references \p sel. * * The reference count of \p sel is updated, but no other modifications are * made. */ SelectionTreeElementPointer _gmx_sel_init_variable_ref(const gmx::SelectionTreeElementPointer &sel) { SelectionTreeElementPointer ref; if (sel->v.type == POS_VALUE && sel->type == SEL_CONST) { ref = sel; } else { ref.reset(new SelectionTreeElement(SEL_SUBEXPRREF)); _gmx_selelem_set_vtype(ref, sel->v.type); ref->setName(sel->name()); ref->child = sel; } return ref; }
/*! * \param pparams List of parameters from the selection parser. * \param[in] nparam Number of parameters in \p params. * \param params Array of parameters to parse. * \param root Selection element to which child expressions are added. * \param[in] scanner Scanner data structure. * * Initializes the \p params array based on the parameters in \p pparams. * See the documentation of \c gmx_ana_selparam_t for different options * available for parsing. * * The list \p pparams and any associated values are freed after the parameters * have been processed, no matter is there was an error or not. */ void _gmx_sel_parse_params(const gmx::SelectionParserParameterList &pparams, int nparam, gmx_ana_selparam_t *params, const gmx::SelectionTreeElementPointer &root, void *scanner) { ExceptionInitializer errors(""); /* Check that the value pointers of SPAR_VARNUM parameters are NULL and * that they are not NULL for other parameters */ for (int i = 0; i < nparam; ++i) { if (params[i].val.type != POS_VALUE && (params[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL))) { GMX_RELEASE_ASSERT(params[i].val.u.ptr == NULL, "value pointer is not NULL " "although it should be for SPAR_VARNUM " "and SPAR_ATOMVAL parameters"); GMX_RELEASE_ASSERT(!((params[i].flags & SPAR_VARNUM) && (params[i].flags & SPAR_DYNAMIC)) || params[i].nvalptr != NULL, "nvalptr is NULL but both " "SPAR_VARNUM and SPAR_DYNAMIC are specified"); } else { GMX_RELEASE_ASSERT(params[i].val.u.ptr != NULL, "value pointer is NULL"); } } /* Parse the parameters */ int nullParamIndex = 0; SelectionParserParameterList::const_iterator pparam; for (pparam = pparams.begin(); pparam != pparams.end(); ++pparam) { try { // Always assigned afterwards, but cppcheck does not see that. gmx_ana_selparam_t *oparam = NULL; /* Find the parameter and make some checks */ if (!pparam->name().empty()) { nullParamIndex = -1; oparam = gmx_ana_selparam_find(pparam->name().c_str(), nparam, params); GMX_RELEASE_ASSERT(oparam != NULL, "Inconsistent selection parameter"); } else if (nullParamIndex >= 0) { oparam = ¶ms[nullParamIndex]; if (oparam->name != NULL) { std::string text(_gmx_sel_lexer_get_text(scanner, pparam->location())); std::string message = formatString("Unexpected '%s'", text.c_str()); GMX_THROW(InvalidInputError(message)); } ++nullParamIndex; } else { GMX_RELEASE_ASSERT(false, "All NULL parameters should appear in " "the beginning of the list"); } if (oparam->flags & SPAR_SET) { std::string message = formatString("'%s' appears multiple times", pparam->name().c_str()); GMX_THROW(InvalidInputError(message)); } oparam->flags |= SPAR_SET; if (oparam->val.type != NO_VALUE && pparam->values().empty()) { std::string text; if (pparam->name().empty()) { text = root->name(); } else { text = _gmx_sel_lexer_get_text(scanner, pparam->location()); } std::string message = formatString("'%s' should be followed by a value/expression", text.c_str()); GMX_THROW(InvalidInputError(message)); } /* Process the values for the parameter */ convert_const_values(pparam->values_.get()); convert_values(pparam->values_.get(), oparam->val.type, scanner); if (oparam->val.type == NO_VALUE) { parse_values_bool(pparam->name(), pparam->values(), oparam, scanner); } else if (oparam->flags & SPAR_RANGES) { parse_values_range(pparam->values(), oparam, scanner); } else if (oparam->flags & SPAR_VARNUM) { if (pparam->values().size() == 1 && pparam->values().front().hasExpressionValue()) { parse_values_varnum_expr(pparam->values(), oparam, root, scanner); } else { parse_values_varnum(pparam->values(), oparam, root, scanner); } } else if (oparam->flags & SPAR_ENUMVAL) { parse_values_enum(pparam->values(), oparam, scanner); } else { parse_values_std(pparam->values(), oparam, root, scanner); } } catch (UserInputError &ex) { if (!pparam->name().empty()) { std::string text(_gmx_sel_lexer_get_text(scanner, pparam->location())); ex.prependContext(formatString("In '%s'", text.c_str())); } errors.addCurrentExceptionAsNested(); } } /* Check that all required parameters are present */ for (int i = 0; i < nparam; ++i) { if (!(params[i].flags & SPAR_OPTIONAL) && !(params[i].flags & SPAR_SET)) { std::string message; if (params[i].name == NULL) { message = formatString("'%s' should be followed by a value/expression", root->name().c_str()); } else { message = formatString("'%s' is missing", params[i].name); } InvalidInputError ex(message); errors.addNested(ex); } } if (errors.hasNestedExceptions()) { GMX_THROW(InvalidInputError(errors)); } }