/*! * \param[in] sc Selection collection (used for position evaluation). * \param[in] method Method to use for initialization. * \param[in] params Pointer to the first parameter. * \param[in] rpost Reference position type to use (NULL = default). * \returns The created selection element. * * This function handles the creation of a \c t_selelem object for * selection methods that take parameters. */ t_selelem * _gmx_sel_init_method(gmx_ana_selcollection_t *sc, gmx_ana_selmethod_t *method, t_selexpr_param *params, const char *rpost) { t_selelem *root; int rc; root = _gmx_selelem_create(SEL_EXPRESSION); set_method(sc, root, method); /* Process the parameters */ if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams, root->u.expr.method->param, root)) { _gmx_selelem_free(root); return NULL; } rc = set_refpos_type(sc->pcc, root, rpost); if (rc != 0) { _gmx_selelem_free(root); return NULL; } return root; }
/*! * \param scanner Scanner data structure. * \param[in] sel The selection element that evaluates the selection. * \returns The created root selection element. * * This function handles the creation of root (\ref SEL_ROOT) \c t_selelem * objects for selections. */ t_selelem * _gmx_sel_init_selection(gmx_sel_lexer_t *scanner, t_selelem *sel) { gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner); t_selelem *root; int rc; if (sel->v.type != POS_VALUE) { gmx_bug("each selection must evaluate to a position"); /* FIXME: Better handling of this error */ return NULL; } root = _gmx_selelem_create(SEL_ROOT); root->child = sel; /* Update the flags */ rc = _gmx_selelem_update_flags(root); if (rc != 0) { _gmx_selelem_free(root); return NULL; } /* Print out some information if the parser is interactive */ if (_gmx_sel_is_lexer_interactive(scanner)) { /* TODO: It would be nice to print the whole selection here */ fprintf(stderr, "Selection parsed\n"); } return root; }
/*! * \param[in] sc Selection collection. * \param[in] left Selection element for the left hand side. * \param[in] right Selection element for the right hand side. * \param[in] cmpop String representation of the comparison operator. * \returns The created selection element. * * This function handles the creation of a \c t_selelem object for * comparison expressions. */ t_selelem * _gmx_sel_init_comparison(gmx_ana_selcollection_t *sc, t_selelem *left, t_selelem *right, char *cmpop) { t_selelem *sel; t_selexpr_param *params, *param; int rc; sel = _gmx_selelem_create(SEL_EXPRESSION); set_method(sc, sel, &sm_compare); /* Create the parameter for the left expression */ params = param = _gmx_selexpr_create_param(left->v.type == INT_VALUE ? "int1" : "real1"); param->nval = 1; param->value = _gmx_selexpr_create_value_expr(left); /* Create the parameter for the right expression */ param = _gmx_selexpr_create_param(right->v.type == INT_VALUE ? "int2" : "real2"); param->nval = 1; param->value = _gmx_selexpr_create_value_expr(right); params->next = param; /* Create the parameter for the operator */ param = _gmx_selexpr_create_param("op"); param->nval = 1; param->value = _gmx_selexpr_create_value(STR_VALUE); param->value->u.s = cmpop; params->next->next = param; if (!_gmx_sel_parse_params(params, sel->u.expr.method->nparams, sel->u.expr.method->param, sel)) { _gmx_selparser_error("error in comparison initialization"); _gmx_selelem_free(sel); return NULL; } return sel; }
/*! * \param[in] sc Selection collection (used for position evaluation). * \param[in] method Method to use. * \param[in] nargs Number of arguments for keyword matching. * \param[in] args Pointer to the first argument. * \param[in] rpost Reference position type to use (NULL = default). * \returns The created selection element. * * This function handles the creation of a \c t_selelem object for * selection methods that do not take parameters. */ t_selelem * _gmx_sel_init_keyword(gmx_ana_selcollection_t *sc, gmx_ana_selmethod_t *method, int nargs, t_selexpr_value *args, const char *rpost) { t_selelem *root, *child; t_selexpr_param *params, *param; int rc; if (method->nparams > 0) { gmx_bug("internal error"); return NULL; } root = _gmx_selelem_create(SEL_EXPRESSION); child = root; set_method(sc, child, method); /* Initialize the evaluation of keyword matching if values are provided */ if (nargs > 0) { gmx_ana_selmethod_t *kwmethod; switch (method->type) { case INT_VALUE: kwmethod = &sm_keyword_int; break; case STR_VALUE: kwmethod = &sm_keyword_str; break; default: _gmx_selparser_error("unknown type for keyword selection"); goto on_error; } root = _gmx_selelem_create(SEL_EXPRESSION); set_method(sc, root, kwmethod); params = param = _gmx_selexpr_create_param(NULL); param->nval = 1; param->value = _gmx_selexpr_create_value_expr(child); param = _gmx_selexpr_create_param(NULL); param->nval = nargs; param->value = args; params->next = param; if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams, root->u.expr.method->param, root)) { _gmx_selparser_error("error in keyword selection initialization"); goto on_error; } } rc = set_refpos_type(sc->pcc, child, rpost); if (rc != 0) { goto on_error; } return root; /* On error, free all memory and return NULL. */ on_error: _gmx_selelem_free(root); return NULL; }
/*! * \param[in] sc Selection collection. * \param[in] method Modifier to use for initialization. * \param[in] params Pointer to the first parameter. * \param[in] sel Selection element that the modifier should act on. * \returns The created selection element. * * This function handles the creation of a \c t_selelem object for * selection modifiers. */ t_selelem * _gmx_sel_init_modifier(gmx_ana_selcollection_t *sc, gmx_ana_selmethod_t *method, t_selexpr_param *params, t_selelem *sel) { t_selelem *root; t_selelem *mod; t_selexpr_param *vparam; int i; mod = _gmx_selelem_create(SEL_MODIFIER); set_method(sc, mod, method); if (method->type == NO_VALUE) { t_selelem *child; child = sel; while (child->next) { child = child->next; } child->next = mod; root = sel; } else { vparam = _gmx_selexpr_create_param(NULL); vparam->nval = 1; vparam->value = _gmx_selexpr_create_value_expr(sel); vparam->next = params; params = vparam; root = mod; } /* Process the parameters */ if (!_gmx_sel_parse_params(params, mod->u.expr.method->nparams, mod->u.expr.method->param, mod)) { if (mod->child != sel) { _gmx_selelem_free(sel); } _gmx_selelem_free(mod); return NULL; } return root; }
/*! * \param[out] selp Pointer to receive a pointer to the created selection * element (set to NULL on error). * \param[in] method Keyword selection method to evaluate. * \param[in] param Parameter that gives the group to evaluate \p method in. * \param[in] scanner Scanner data structure. * \returns 0 on success, non-zero error code on error. * * Creates a \ref SEL_EXPRESSION selection element (pointer put in \c *selp) * that evaluates the keyword method given by \p method in the group given by * \p param. */ int _gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method, t_selexpr_param *param, void *scanner) { t_selelem *sel; t_methoddata_kweval *data; gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner); char buf[1024]; sprintf(buf, "In evaluation of '%s'", method->name); gmx::MessageStringContext context(errors, buf); if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL)) || method->outinit || method->pupdate) { _gmx_selexpr_free_params(param); GMX_ERROR(gmx::eeInternalError, "Unsupported keyword method for arbitrary group evaluation"); } *selp = NULL; sel = _gmx_selelem_create(SEL_EXPRESSION); _gmx_selelem_set_method(sel, method, scanner); snew(data, 1); data->kwmethod = sel->u.expr.method; data->kwmdata = sel->u.expr.mdata; gmx_ana_index_clear(&data->g); snew(sel->u.expr.method, 1); memcpy(sel->u.expr.method, data->kwmethod, sizeof(gmx_ana_selmethod_t)); sel->u.expr.method->flags |= SMETH_VARNUMVAL; sel->u.expr.method->init_data = NULL; sel->u.expr.method->set_poscoll = NULL; sel->u.expr.method->init = method->init ? &init_kweval : NULL; sel->u.expr.method->outinit = &init_output_kweval; sel->u.expr.method->free = &free_data_kweval; sel->u.expr.method->init_frame = method->init_frame ? &init_frame_kweval : NULL; sel->u.expr.method->update = &evaluate_kweval; sel->u.expr.method->pupdate = NULL; sel->u.expr.method->nparams = asize(smparams_kweval); sel->u.expr.method->param = smparams_kweval; _gmx_selelem_init_method_params(sel, scanner); sel->u.expr.mdata = data; sel->u.expr.method->param[0].val.u.g = &data->g; sfree(param->name); param->name = NULL; if (!_gmx_sel_parse_params(param, sel->u.expr.method->nparams, sel->u.expr.method->param, sel, scanner)) { _gmx_selelem_free(sel); return -1; } *selp = sel; return 0; }
/*! * \param[in] first First selection to free. * * Frees \p first and all selections accessible through the * \ref t_selelem::next "first->next" pointer. */ void _gmx_selelem_free_chain(t_selelem *first) { t_selelem *child, *prev; child = first; while (child) { prev = child; child = child->next; _gmx_selelem_free(prev); } }
/*! * \param[in] tab Symbol table to free. * * The pointer \p tab is invalid after the call. */ void _gmx_sel_symtab_free(gmx_sel_symtab_t *tab) { gmx_sel_symrec_t *sym; while (tab->first) { sym = tab->first; tab->first = sym->next; if (sym->type == SYMBOL_VARIABLE) { _gmx_selelem_free(sym->u.var); } sfree(sym->name); sfree(sym); } sfree(tab); }
/*! * \param value Pointer to the beginning of the value list to free. * * The expressions referenced by the values are also freed * (to prevent this, set the expression to NULL before calling the function). */ void _gmx_selexpr_free_values(t_selexpr_value *value) { t_selexpr_value *old; while (value) { if (value->bExpr) { if (value->u.expr) { _gmx_selelem_free(value->u.expr); } } else if (value->type == STR_VALUE) { sfree(value->u.s); } old = value; value = value->next; sfree(old); } }
/*! * \param[in] sc Selection collection. * \param[in] expr Input selection element for the position calculation. * \param[in] type Reference position type or NULL for default. * \param[in] bSelPos Whether the element evaluates the positions for a * selection. * \returns The created selection element. * * This function handles the creation of a \c t_selelem object for * evaluation of reference positions. */ t_selelem * _gmx_sel_init_position(gmx_ana_selcollection_t *sc, t_selelem *expr, const char *type, bool bSelPos) { t_selelem *root; t_selexpr_param *params; int flags; root = _gmx_selelem_create(SEL_EXPRESSION); set_method(sc, root, &sm_keyword_pos); /* Selections use largest static group by default, while * reference positions use the whole residue/molecule. */ flags = bSelPos ? POS_COMPLMAX : POS_COMPLWHOLE; if (bSelPos && sc->bMaskOnly) { flags |= POS_MASKONLY; } /* FIXME: It would be better not to have the string here hardcoded. */ if (type[0] != 'a') { root->u.expr.method->flags |= SMETH_REQTOP; } _gmx_selelem_set_kwpos_type(type, flags, root->u.expr.mdata); /* Create the parameters for the parameter parser. */ params = _gmx_selexpr_create_param(NULL); params->nval = 1; params->value = _gmx_selexpr_create_value_expr(expr); /* Parse the parameters. */ if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams, root->u.expr.method->param, root)) { _gmx_selelem_free(root); return NULL; } return root; }
/*! \brief * Replaces constant expressions with their values. * * \param[in,out] values First element in the value list to process. */ static void convert_const_values(t_selexpr_value *values) { t_selexpr_value *val; val = values; while (val) { if (val->bExpr && val->u.expr->v.type != GROUP_VALUE && val->u.expr->type == SEL_CONST) { t_selelem *expr = val->u.expr; val->bExpr = FALSE; switch (expr->v.type) { case INT_VALUE: val->u.i.i1 = val->u.i.i2 = expr->v.u.i[0]; break; case REAL_VALUE: val->u.r.r1 = val->u.r.r2 = expr->v.u.r[0]; break; case STR_VALUE: val->u.s = expr->v.u.s[0]; break; case POS_VALUE: copy_rvec(expr->v.u.p->x[0], val->u.x); break; default: gmx_bug("internal error"); break; } _gmx_selelem_free(expr); } val = val->next; } }
/*! * \param scanner Scanner data structure. * \param[in] name Name of the variable (should not be freed after this * function). * \param[in] expr The selection element that evaluates the variable. * \returns The created root selection element. * * This function handles the creation of root \c t_selelem objects for * variable assignments. A \ref SEL_ROOT element and a \ref SEL_SUBEXPR * element are both created. */ t_selelem * _gmx_sel_assign_variable(gmx_sel_lexer_t *scanner, char *name, t_selelem *expr) { gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner); t_selelem *root; int rc; rc = _gmx_selelem_update_flags(expr); if (rc != 0) { sfree(name); _gmx_selelem_free(expr); return NULL; } /* Check if this is a constant non-group value */ if (expr->type == SEL_CONST && expr->v.type != GROUP_VALUE) { /* If so, just assign the constant value to the variable */ if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr)) { _gmx_selelem_free(expr); sfree(name); return NULL; } _gmx_selelem_free(expr); if (_gmx_sel_is_lexer_interactive(scanner)) { fprintf(stderr, "Variable '%s' parsed\n", name); } sfree(name); return NULL; } /* Check if we are assigning a variable to another variable */ if (expr->type == SEL_SUBEXPRREF) { /* If so, make a simple alias */ if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr->child)) { _gmx_selelem_free(expr); sfree(name); return NULL; } _gmx_selelem_free(expr); if (_gmx_sel_is_lexer_interactive(scanner)) { fprintf(stderr, "Variable '%s' parsed\n", name); } sfree(name); return NULL; } /* Create the root element */ root = _gmx_selelem_create(SEL_ROOT); root->name = name; root->u.cgrp.name = name; /* Create the subexpression element */ root->child = _gmx_selelem_create(SEL_SUBEXPR); _gmx_selelem_set_vtype(root->child, expr->v.type); root->child->name = name; root->child->child = expr; /* Update flags */ rc = _gmx_selelem_update_flags(root); if (rc != 0) { _gmx_selelem_free(root); return NULL; } /* Add the variable to the symbol table */ if (!_gmx_sel_add_var_symbol(sc->symtab, name, root->child)) { _gmx_selelem_free(root); return NULL; } if (_gmx_sel_is_lexer_interactive(scanner)) { fprintf(stderr, "Variable '%s' parsed\n", name); } return root; }
/*! \brief * Adds a new subexpression reference to a selection element. * * \param[in,out] root Root element to which the subexpression is added. * \param[in] param Parameter for which this expression is a value. * \param[in] expr Expression to add. * \returns The created child element. * * Creates a new \ref SEL_SUBEXPRREF element and adds it into the child * list of \p root. * If \p expr is already a \ref SEL_SUBEXPRREF, it is used as it is. * \ref SEL_ALLOCVAL is cleared for the returned element. */ static t_selelem * add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr) { t_selelem *child; int rc; if (root->type != SEL_EXPRESSION && root->type != SEL_MODIFIER) { gmx_bug("unsupported root element for selection parameter parser"); return NULL; } /* Create a subexpression reference element if necessary */ if (expr->type == SEL_SUBEXPRREF) { child = expr; } else { child = _gmx_selelem_create(SEL_SUBEXPRREF); if (!child) { return NULL; } _gmx_selelem_set_vtype(child, expr->v.type); child->child = expr; } /* Setup the child element */ child->flags &= ~SEL_ALLOCVAL; child->u.param = param; if (child->v.type != param->val.type) { _gmx_selparser_error("invalid expression value for parameter '%s'", param->name); goto on_error; } rc = _gmx_selelem_update_flags(child); if (rc != 0) { goto on_error; } if ((child->flags & SEL_DYNAMIC) && !(param->flags & SPAR_DYNAMIC)) { _gmx_selparser_error("parameter '%s' does not support dynamic values", param->name); goto on_error; } if (!(child->flags & SEL_DYNAMIC)) { param->flags &= ~SPAR_DYNAMIC; } /* Put the child element in the correct place */ place_child(root, child, param); return child; on_error: if (child != expr) { _gmx_selelem_free(child); } return NULL; }