Merge remote-tracking branch 'origin/release-4-6' into HEAD
[alexxy/gromacs.git] / src / gromacs / selection / symrec.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
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.
13
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.
18  *
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.
25  *
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.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements functions in symrec.h.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_selection
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <macros.h>
43 #include <smalloc.h>
44 #include <string2.h>
45 #include <typedefs.h>
46 #include <gmx_fatal.h>
47
48 #include "gromacs/selection/poscalc.h"
49
50 #include "selelem.h"
51 #include "symrec.h"
52
53 /*! \internal \brief
54  * Symbol table for the selection parser.
55  */
56 struct gmx_sel_symtab_t
57 {
58     /** Pointer to the first symbol in the linked list of symbols. */
59     gmx_sel_symrec_t *first;
60 };
61
62 /*! \internal \brief
63  * Single symbol for the selection parser.
64  */
65 struct gmx_sel_symrec_t
66 {
67     /** Name of the symbol. */
68     char                           *name;
69     /** Type of the symbol. */
70     e_symbol_t                      type;
71     /** Value of the symbol. */
72     union {
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         struct t_selelem           *var;
77     }                               u;
78     /** Pointer to the next symbol. */
79     struct gmx_sel_symrec_t        *next;
80 };
81
82 /** List of reserved symbols to register in add_reserved_symbols(). */
83 static const char *const sym_reserved[] = {
84     "group",
85     "to",
86     "not",
87     "and",
88     "or",
89     "xor",
90     "yes",
91     "no",
92     "on",
93     "off",
94     "help",
95 };
96
97 /*!
98  * \param[in] sym Symbol to query.
99  * \returns   The name of \p sym.
100  *
101  * The returned pointer should not be free'd.
102  */
103 char *
104 _gmx_sel_sym_name(gmx_sel_symrec_t *sym)
105 {
106     return sym->name;
107 }
108
109 /*!
110  * \param[in] sym Symbol to query.
111  * \returns   The type of \p sym.
112  */
113 e_symbol_t
114 _gmx_sel_sym_type(gmx_sel_symrec_t *sym)
115 {
116     return sym->type;
117 }
118
119 /*!
120  * \param[in] sym Symbol to query.
121  * \returns   The method associated with \p sym, or NULL if \p sym is not a
122  *   \ref SYMBOL_METHOD symbol.
123  */
124 struct gmx_ana_selmethod_t *
125 _gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
126 {
127     if (sym->type != SYMBOL_METHOD)
128     {
129         gmx_call("symbol is not a method symbol");
130         return NULL;
131     }
132     return sym->u.meth;
133 }
134
135 /*!
136  * \param[in] sym Symbol to query.
137  * \returns   The variable expression associated with \p sym, or NULL if
138  *   \p sym is not a \ref SYMBOL_VARIABLE symbol.
139  */
140 struct t_selelem *
141 _gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
142 {
143     if (sym->type != SYMBOL_VARIABLE)
144     {
145         gmx_call("symbol is not a variable symbol");
146         return NULL;
147     }
148     return sym->u.var;
149 }
150
151 /*! \brief
152  * Adds the reserved symbols to a symbol table.
153  * 
154  * \param[in,out] tab  Symbol table to which the symbols are added.
155  *
156  * Assumes that the symbol table is empty.
157  */
158 static void
159 add_reserved_symbols(gmx_sel_symtab_t *tab)
160 {
161     gmx_sel_symrec_t *sym;
162     gmx_sel_symrec_t *last;
163     size_t            i;
164
165     last = NULL;
166     for (i = 0; i < asize(sym_reserved); ++i)
167     {
168         snew(sym, 1);
169         sym->name = strdup(sym_reserved[i]);
170         sym->type = SYMBOL_RESERVED;
171         sym->next = NULL;
172         if (last)
173         {
174             last->next = sym;
175         }
176         else
177         {
178             tab->first = sym;
179         }
180         last = sym;
181     }
182 }
183
184 /*! \brief
185  * Adds the position symbols to the symbol list.
186  * 
187  * \param[in,out] tab  Symbol table to which the symbols are added.
188  */
189 static void
190 add_position_symbols(gmx_sel_symtab_t *tab)
191 {
192     gmx_sel_symrec_t  *sym;
193     gmx_sel_symrec_t  *last;
194     int                i;
195
196     const char *const *postypes
197         = gmx::PositionCalculationCollection::typeEnumValues;
198     last = tab->first;
199     while (last && last->next)
200     {
201         last = last->next;
202     }
203     for (i = 0; postypes[i] != NULL; ++i)
204     {
205         snew(sym, 1);
206         sym->name = strdup(postypes[i]);
207         sym->type = SYMBOL_POS;
208         sym->next = NULL;
209         if (last)
210         {
211             last->next = sym;
212         }
213         else
214         {
215             tab->first = sym;
216         }
217         last = sym;
218     }
219 }
220
221 /*!
222  * \param[out] tabp Symbol table pointer to initialize.
223  *
224  * Reserved and position symbols are added to the created table.
225  */
226 int
227 _gmx_sel_symtab_create(gmx_sel_symtab_t **tabp)
228 {
229     gmx_sel_symtab_t *tab;
230
231     snew(tab, 1);
232     add_reserved_symbols(tab);
233     add_position_symbols(tab);
234     *tabp = tab;
235     return 0;
236 }
237
238 /*!
239  * \param[in] tab Symbol table to free.
240  *
241  * The pointer \p tab is invalid after the call.
242  */
243 void
244 _gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
245 {
246     gmx_sel_symrec_t *sym;
247
248     while (tab->first)
249     {
250         sym = tab->first;
251         tab->first = sym->next;
252         if (sym->type == SYMBOL_VARIABLE)
253         {
254             _gmx_selelem_free(sym->u.var);
255         }
256         sfree(sym->name);
257         sfree(sym);
258     }
259     sfree(tab);
260 }
261
262 /*!
263  * \param[in] tab    Symbol table to search.
264  * \param[in] name   Symbol name to find.
265  * \param[in] bExact If false, symbols that begin with \p name are also
266  *   considered.
267  * \returns   Pointer to the symbol with name \p name, or NULL if not found.
268  *
269  * If no exact match is found and \p bExact is false, returns a symbol that
270  * begins with \p name if a unique matching symbol is found.
271  */
272 gmx_sel_symrec_t *
273 _gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, bool bExact)
274 {
275     return _gmx_sel_find_symbol_len(tab, name, strlen(name), bExact);
276 }
277
278 /*!
279  * \param[in] tab    Symbol table to search.
280  * \param[in] name   Symbol name to find.
281  * \param[in] len    Only consider the first \p len characters of \p name.
282  * \param[in] bExact If false, symbols that begin with \p name are also
283  *   considered.
284  * \returns   Pointer to the symbol with name \p name, or NULL if not found.
285  *
286  * If no exact match is found and \p bExact is false, returns a symbol that
287  * begins with \p name if a unique matching symbol is found.
288  *
289  * The parameter \p len is there to allow using this function from scanner.l
290  * without modifying the text to be scanned or copying it.
291  */
292 gmx_sel_symrec_t *
293 _gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
294                          bool bExact)
295 {
296     gmx_sel_symrec_t *sym;
297     gmx_sel_symrec_t *match;
298     bool              bUnique;
299     bool              bMatch;
300
301     match = NULL;
302     bUnique = true;
303     bMatch  = false;
304     sym = tab->first;
305     while (sym)
306     {
307         if (!strncmp(sym->name, name, len))
308         {
309             if (strlen(sym->name) == len)
310             {
311                 return sym;
312             }
313             if (bMatch)
314             {
315                 bUnique = false;
316             }
317             bMatch = true;
318             if (sym->type == SYMBOL_METHOD)
319             {
320                 match = sym;
321             }
322         }
323         sym = sym->next;
324     }
325     if (bExact)
326     {
327         return NULL;
328     }
329
330     if (!bUnique)
331     {
332         fprintf(stderr, "parse error: ambiguous symbol\n");
333         return NULL;
334     }
335     return match;
336 }
337
338 /*!
339  * \param[in] tab   Symbol table to search.
340  * \param[in] type  Type of symbol to find.
341  * \returns   The first symbol in \p tab with type \p type,
342  *   or NULL if there are no such symbols.
343  */
344 gmx_sel_symrec_t *
345 _gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type)
346 {
347     gmx_sel_symrec_t *sym;
348
349     sym = tab->first;
350     while (sym)
351     {
352         if (sym->type == type)
353         {
354             return sym;
355         }
356         sym = sym->next;
357     }
358     return NULL;
359 }
360
361 /*!
362  * \param[in] after Start the search after this symbol.
363  * \param[in] type  Type of symbol to find.
364  * \returns   The next symbol after \p after with type \p type,
365  *   or NULL if there are no more symbols.
366  */
367 gmx_sel_symrec_t *
368 _gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type)
369 {
370     gmx_sel_symrec_t *sym;
371
372     sym = after->next;
373     while (sym)
374     {
375         if (sym->type == type)
376         {
377             return sym;
378         }
379         sym = sym->next;
380     }
381     return NULL;
382 }
383
384 /*! \brief
385  * Internal utility function used in adding symbols to a symbol table.
386  *
387  * \param[in,out] tab   Symbol table to add the symbol to.
388  * \param[in]     name  Name of the symbol to add.
389  * \param[out]    ctype On error, the type of the conflicting symbol is
390  *   written to \p *ctype.
391  * \returns       Pointer to the new symbol record, or NULL if \p name
392  *   conflicts with an existing symbol.
393  */
394 static gmx_sel_symrec_t *
395 add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
396 {
397     gmx_sel_symrec_t *sym, *psym;
398
399     /* Check if there is a conflicting symbol */
400     psym = NULL;
401     sym  = tab->first;
402     while (sym)
403     {
404         if (!gmx_strcasecmp(sym->name, name))
405         {
406             *ctype = sym->type;
407             return NULL;
408         }
409         psym = sym;
410         sym  = sym->next;
411     }
412
413     /* Create a new symbol record */
414     if (psym == NULL)
415     {
416         snew(tab->first, 1);
417         sym = tab->first;
418     }
419     else
420     {
421         snew(psym->next, 1);
422         sym = psym->next;
423     }
424     sym->name = strdup(name);
425     return sym;
426 }
427
428 /*!
429  * \param[in,out] tab    Symbol table to add the symbol to.
430  * \param[in]     name   Name of the new symbol.
431  * \param[in]     sel    Value of the variable.
432  * \returns       Pointer to the created symbol record, or NULL if there was a
433  *   symbol with the same name.
434  */
435 gmx_sel_symrec_t *
436 _gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
437                         struct t_selelem *sel)
438 {
439     gmx_sel_symrec_t *sym;
440     e_symbol_t        ctype;
441
442     sym = add_symbol(tab, name, &ctype);
443     if (!sym)
444     {
445         fprintf(stderr, "parse error: ");
446         switch (ctype)
447         {
448             case SYMBOL_RESERVED:
449             case SYMBOL_POS:
450                 fprintf(stderr, "variable name (%s) conflicts with a reserved keyword\n",
451                         name);
452                 break;
453             case SYMBOL_VARIABLE:
454                 fprintf(stderr, "duplicate variable name (%s)\n", name);
455                 break;
456             case SYMBOL_METHOD:
457                 fprintf(stderr, "variable name (%s) conflicts with a selection keyword\n",
458                         name);
459                 break;
460         }
461         return NULL;
462     }
463
464     sym->type  = SYMBOL_VARIABLE;
465     sym->u.var = sel;
466     sel->refcount++;
467     return sym;
468 }
469
470 /*!
471  * \param[in,out] tab    Symbol table to add the symbol to.
472  * \param[in]     name   Name of the new symbol.
473  * \param[in]     method Method that this symbol represents.
474  * \returns       Pointer to the created symbol record, or NULL if there was a
475  *   symbol with the same name.
476  */
477 gmx_sel_symrec_t *
478 _gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
479                            struct gmx_ana_selmethod_t *method)
480 {
481     gmx_sel_symrec_t *sym;
482     e_symbol_t        ctype;
483
484     sym = add_symbol(tab, name, &ctype);
485     if (!sym)
486     {
487         fprintf(stderr, "parse error: ");
488         switch (ctype)
489         {
490             case SYMBOL_RESERVED:
491             case SYMBOL_POS:
492                 fprintf(stderr, "method name (%s) conflicts with a reserved keyword\n",
493                         name);
494                 break;
495             case SYMBOL_VARIABLE:
496                 fprintf(stderr, "method name (%s) conflicts with a variable name\n",
497                         name);
498                 break;
499             case SYMBOL_METHOD:
500                 fprintf(stderr, "duplicate method name (%s)\n", name);
501                 break;
502         }
503         return NULL;
504     }
505
506     sym->type   = SYMBOL_METHOD;
507     sym->u.meth = method;
508     return sym;
509 }