3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
33 * Implements functions in symrec.h.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_selection
42 #include "gromacs/legacyheaders/macros.h"
43 #include "gromacs/legacyheaders/smalloc.h"
44 #include "gromacs/legacyheaders/string2.h"
46 #include "gromacs/selection/poscalc.h"
47 #include "gromacs/utility/gmxassert.h"
53 * Symbol table for the selection parser.
55 struct gmx_sel_symtab_t
57 /** Pointer to the first symbol in the linked list of symbols. */
58 gmx_sel_symrec_t *first;
62 * Single symbol for the selection parser.
65 * Make this a proper class.
67 struct gmx_sel_symrec_t
69 /** Name of the symbol. */
71 /** Type of the symbol. */
73 /** Pointer to the method structure (\ref SYMBOL_METHOD). */
74 struct gmx_ana_selmethod_t *meth;
75 /** Pointer to the variable value (\ref SYMBOL_VARIABLE). */
76 gmx::SelectionTreeElementPointer var;
77 /** Pointer to the next symbol. */
78 struct gmx_sel_symrec_t *next;
81 /** List of reserved symbols to register in add_reserved_symbols(). */
82 static const char *const sym_reserved[] = {
97 * \param[in] sym Symbol to query.
98 * \returns The name of \p sym.
100 * The returned pointer should not be free'd.
103 _gmx_sel_sym_name(gmx_sel_symrec_t *sym)
109 * \param[in] sym Symbol to query.
110 * \returns The type of \p sym.
113 _gmx_sel_sym_type(gmx_sel_symrec_t *sym)
119 * \param[in] sym Symbol to query.
120 * \returns The method associated with \p sym, or NULL if \p sym is not a
121 * \ref SYMBOL_METHOD symbol.
123 struct gmx_ana_selmethod_t *
124 _gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
126 GMX_RELEASE_ASSERT(sym->type == SYMBOL_METHOD,
127 "Attempting to get method handle for a non-method symbol");
132 * \param[in] sym Symbol to query.
133 * \returns The variable expression associated with \p sym, or NULL if
134 * \p sym is not a \ref SYMBOL_VARIABLE symbol.
136 const gmx::SelectionTreeElementPointer &
137 _gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
139 GMX_RELEASE_ASSERT(sym->type == SYMBOL_VARIABLE,
140 "Attempting to get variable value for a non-variable symbol");
145 * Adds the reserved symbols to a symbol table.
147 * \param[in,out] tab Symbol table to which the symbols are added.
149 * Assumes that the symbol table is empty.
152 add_reserved_symbols(gmx_sel_symtab_t *tab)
154 gmx_sel_symrec_t *last;
158 for (i = 0; i < asize(sym_reserved); ++i)
160 gmx_sel_symrec_t *sym = new gmx_sel_symrec_t();
161 sym->name = strdup(sym_reserved[i]);
162 sym->type = SYMBOL_RESERVED;
178 * Adds the position symbols to the symbol list.
180 * \param[in,out] tab Symbol table to which the symbols are added.
183 add_position_symbols(gmx_sel_symtab_t *tab)
185 gmx_sel_symrec_t *last;
188 const char *const *postypes
189 = gmx::PositionCalculationCollection::typeEnumValues;
191 while (last && last->next)
195 for (i = 0; postypes[i] != NULL; ++i)
197 gmx_sel_symrec_t *sym = new gmx_sel_symrec_t();
198 sym->name = strdup(postypes[i]);
199 sym->type = SYMBOL_POS;
215 * \param[out] tabp Symbol table pointer to initialize.
217 * Reserved and position symbols are added to the created table.
220 _gmx_sel_symtab_create(gmx_sel_symtab_t **tabp)
222 gmx_sel_symtab_t *tab;
225 add_reserved_symbols(tab);
226 add_position_symbols(tab);
232 * \param[in] tab Symbol table to free.
234 * The pointer \p tab is invalid after the call.
237 _gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
239 gmx_sel_symrec_t *sym;
244 tab->first = sym->next;
252 * \param[in] tab Symbol table to search.
253 * \param[in] name Symbol name to find.
254 * \param[in] bExact If false, symbols that begin with \p name are also
256 * \returns Pointer to the symbol with name \p name, or NULL if not found.
258 * If no exact match is found and \p bExact is false, returns a symbol that
259 * begins with \p name if a unique matching symbol is found.
262 _gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, bool bExact)
264 return _gmx_sel_find_symbol_len(tab, name, strlen(name), bExact);
268 * \param[in] tab Symbol table to search.
269 * \param[in] name Symbol name to find.
270 * \param[in] len Only consider the first \p len characters of \p name.
271 * \param[in] bExact If false, symbols that begin with \p name are also
273 * \returns Pointer to the symbol with name \p name, or NULL if not found.
275 * If no exact match is found and \p bExact is false, returns a symbol that
276 * begins with \p name if a unique matching symbol is found.
278 * The parameter \p len is there to allow using this function from scanner.l
279 * without modifying the text to be scanned or copying it.
282 _gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
285 gmx_sel_symrec_t *sym;
286 gmx_sel_symrec_t *match;
296 if (!strncmp(sym->name, name, len))
298 if (strlen(sym->name) == len)
307 if (sym->type == SYMBOL_METHOD)
321 fprintf(stderr, "parse error: ambiguous symbol\n");
328 * \param[in] tab Symbol table to search.
329 * \param[in] type Type of symbol to find.
330 * \returns The first symbol in \p tab with type \p type,
331 * or NULL if there are no such symbols.
334 _gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type)
336 gmx_sel_symrec_t *sym;
341 if (sym->type == type)
351 * \param[in] after Start the search after this symbol.
352 * \param[in] type Type of symbol to find.
353 * \returns The next symbol after \p after with type \p type,
354 * or NULL if there are no more symbols.
357 _gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type)
359 gmx_sel_symrec_t *sym;
364 if (sym->type == type)
374 * Internal utility function used in adding symbols to a symbol table.
376 * \param[in,out] tab Symbol table to add the symbol to.
377 * \param[in] name Name of the symbol to add.
378 * \param[out] ctype On error, the type of the conflicting symbol is
379 * written to \p *ctype.
380 * \returns Pointer to the new symbol record, or NULL if \p name
381 * conflicts with an existing symbol.
383 static gmx_sel_symrec_t *
384 add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
386 gmx_sel_symrec_t *sym, *psym;
388 /* Check if there is a conflicting symbol */
393 if (!gmx_strcasecmp(sym->name, name))
402 /* Create a new symbol record */
405 tab->first = new gmx_sel_symrec_t();
410 psym->next = new gmx_sel_symrec_t();
413 sym->name = strdup(name);
420 * \param[in,out] tab Symbol table to add the symbol to.
421 * \param[in] name Name of the new symbol.
422 * \param[in] sel Value of the variable.
423 * \returns Pointer to the created symbol record, or NULL if there was a
424 * symbol with the same name.
427 _gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
428 const gmx::SelectionTreeElementPointer &sel)
430 gmx_sel_symrec_t *sym;
433 sym = add_symbol(tab, name, &ctype);
436 fprintf(stderr, "parse error: ");
439 case SYMBOL_RESERVED:
441 fprintf(stderr, "variable name (%s) conflicts with a reserved keyword\n",
444 case SYMBOL_VARIABLE:
445 fprintf(stderr, "duplicate variable name (%s)\n", name);
448 fprintf(stderr, "variable name (%s) conflicts with a selection keyword\n",
455 sym->type = SYMBOL_VARIABLE;
461 * \param[in,out] tab Symbol table to add the symbol to.
462 * \param[in] name Name of the new symbol.
463 * \param[in] method Method that this symbol represents.
464 * \returns Pointer to the created symbol record, or NULL if there was a
465 * symbol with the same name.
468 _gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
469 struct gmx_ana_selmethod_t *method)
471 gmx_sel_symrec_t *sym;
474 sym = add_symbol(tab, name, &ctype);
477 fprintf(stderr, "parse error: ");
480 case SYMBOL_RESERVED:
482 fprintf(stderr, "method name (%s) conflicts with a reserved keyword\n",
485 case SYMBOL_VARIABLE:
486 fprintf(stderr, "method name (%s) conflicts with a variable name\n",
490 fprintf(stderr, "duplicate method name (%s)\n", name);
496 sym->type = SYMBOL_METHOD;