/*! * \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 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; }
/*! * \param[in,out] sel Root of the selection element tree to initialize. * \returns 0 on success, an error code on error. * * Propagates the \ref SEL_DYNAMIC flag from the children of \p sel to \p sel * (if any child of \p sel is dynamic, \p sel is also marked as such). * The \ref SEL_DYNAMIC flag is also set for \ref SEL_EXPRESSION elements with * a dynamic method. * Also, sets one of the \ref SEL_SINGLEVAL, \ref SEL_ATOMVAL, or * \ref SEL_VARNUMVAL flags, either based on the children or on the type of * the selection method. * If the types of the children conflict, an error is returned. * * The flags of the children of \p sel are also updated if not done earlier. * The flags are initialized only once for any element; if \ref SEL_FLAGSSET * is set for an element, the function returns immediately, and the recursive * operation does not descend beyond such elements. */ int _gmx_selelem_update_flags(t_selelem *sel) { t_selelem *child; int rc; bool bUseChildType; /* Return if the flags have already been set */ if (sel->flags & SEL_FLAGSSET) { return 0; } /* Set the flags based on the current element type */ switch (sel->type) { case SEL_CONST: sel->flags |= SEL_SINGLEVAL; bUseChildType = FALSE; break; case SEL_EXPRESSION: if (sel->u.expr.method->flags & SMETH_DYNAMIC) { sel->flags |= SEL_DYNAMIC; } if (sel->u.expr.method->flags & SMETH_SINGLEVAL) { sel->flags |= SEL_SINGLEVAL; } else if (sel->u.expr.method->flags & SMETH_VARNUMVAL) { sel->flags |= SEL_VARNUMVAL; } else { sel->flags |= SEL_ATOMVAL; } bUseChildType = FALSE; break; case SEL_MODIFIER: if (sel->v.type != NO_VALUE) { sel->flags |= SEL_VARNUMVAL; } bUseChildType = FALSE; break; case SEL_ROOT: bUseChildType = FALSE; break; default: bUseChildType = TRUE; break; } /* Loop through children to propagate their flags upwards */ child = sel->child; while (child) { /* Update the child */ rc = _gmx_selelem_update_flags(child); if (rc != 0) { return rc; } /* Propagate the dynamic flag */ sel->flags |= (child->flags & SEL_DYNAMIC); /* Propagate the type flag if necessary and check for problems */ if (bUseChildType) { if ((sel->flags & SEL_VALTYPEMASK) && !(sel->flags & child->flags & SEL_VALTYPEMASK)) { _gmx_selparser_error("invalid combination of selection expressions"); return EINVAL; } sel->flags |= (child->flags & SEL_VALTYPEMASK); } child = child->next; } /* Mark that the flags are set */ sel->flags |= SEL_FLAGSSET; /* For root elements, the type should be propagated here, after the * children have been updated. */ if (sel->type == SEL_ROOT) { sel->flags |= (sel->child->flags & SEL_VALTYPEMASK); } return 0; }
/*! \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; }