/*! \brief * Initializes the method for a \ref SEL_EXPRESSION selection element. * * \param[in] sc Selection collection. * \param[in,out] sel Selection element to initialize. * \param[in] method Selection method to set. * * Makes a copy of \p method and stores it in \p sel->u.expr.method, * and calls init_method_params(); */ static void set_method(gmx_ana_selcollection_t *sc, t_selelem *sel, gmx_ana_selmethod_t *method) { int i; _gmx_selelem_set_vtype(sel, method->type); sel->name = method->name; snew(sel->u.expr.method, 1); memcpy(sel->u.expr.method, method, sizeof(gmx_ana_selmethod_t)); init_method_params(sc, sel); }
/*! * \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; }
/*! \brief * Parses the values for a parameter that takes a variable number of values. * * \param[in] nval Number of values in \p values. * \param[in] values Pointer to the list of values. * \param param Parameter to parse. * \param root Selection element to which child expressions are added. * \returns TRUE if the values were parsed successfully, FALSE otherwise. * * For integer ranges, the sequence of numbers from the first to second value * is stored, each as a separate value. */ static gmx_bool parse_values_varnum(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param, t_selelem *root) { t_selexpr_value *value; int i, j; param->flags &= ~SPAR_DYNAMIC; /* Update nval if there are integer ranges. */ if (param->val.type == INT_VALUE) { value = values; while (value) { if (value->type == INT_VALUE && !value->bExpr) { nval += abs(value->u.i.i2 - value->u.i.i1); } value = value->next; } } /* Check that the value type is actually implemented */ if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE && param->val.type != STR_VALUE && param->val.type != POS_VALUE) { gmx_bug("internal error"); return FALSE; } /* Reserve appropriate amount of memory */ if (param->val.type == POS_VALUE) { gmx_ana_pos_reserve(param->val.u.p, nval, 0); gmx_ana_pos_set_nr(param->val.u.p, nval); gmx_ana_indexmap_init(¶m->val.u.p->m, NULL, NULL, INDEX_UNKNOWN); } else { _gmx_selvalue_reserve(¶m->val, nval); } value = values; i = 0; while (value) { if (value->bExpr) { _gmx_selparser_error("expressions not supported within value lists"); return FALSE; } if (value->type != param->val.type) { gmx_bug("internal error"); return FALSE; } switch (param->val.type) { case INT_VALUE: if (value->u.i.i1 <= value->u.i.i2) { for (j = value->u.i.i1; j <= value->u.i.i2; ++j) { param->val.u.i[i++] = j; } } else { for (j = value->u.i.i1; j >= value->u.i.i2; --j) { param->val.u.i[i++] = j; } } break; case REAL_VALUE: if (value->u.r.r1 != value->u.r.r2) { _gmx_selparser_error("real ranges not supported for parameter '%s'", param->name); return FALSE; } param->val.u.r[i++] = value->u.r.r1; break; case STR_VALUE: param->val.u.s[i++] = strdup(value->u.s); break; case POS_VALUE: copy_rvec(value->u.x, param->val.u.p->x[i++]); break; default: /* Should not be reached */ gmx_bug("internal error"); return FALSE; } value = value->next; } param->val.nr = i; if (param->nvalptr) { *param->nvalptr = param->val.nr; } param->nvalptr = NULL; /* Create a dummy child element to store the string values. * This element is responsible for freeing the values, but carries no * other function. */ if (param->val.type == STR_VALUE) { t_selelem *child; child = _gmx_selelem_create(SEL_CONST); _gmx_selelem_set_vtype(child, STR_VALUE); child->name = param->name; child->flags &= ~SEL_ALLOCVAL; child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA; child->v.nr = param->val.nr; _gmx_selvalue_setstore(&child->v, param->val.u.s); /* Because the child is not group-valued, the u union is not used * for anything, so we can abuse it by storing the parameter value * as place_child() expects, but this is really ugly... */ child->u.param = param; place_child(root, child, param); } return TRUE; }