Merge remote-tracking branch 'gerrit/release-4-6' into master
[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     const char       **postypes;
193     gmx_sel_symrec_t  *sym;
194     gmx_sel_symrec_t  *last;
195     int                i;
196
197     postypes = gmx_ana_poscalc_create_type_enum(true);
198     last = tab->first;
199     while (last && last->next)
200     {
201         last = last->next;
202     }
203     for (i = 1; 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     sfree(postypes);
220 }
221
222 /*!
223  * \param[out] tabp Symbol table pointer to initialize.
224  *
225  * Reserved and position symbols are added to the created table.
226  */
227 int
228 _gmx_sel_symtab_create(gmx_sel_symtab_t **tabp)
229 {
230     gmx_sel_symtab_t *tab;
231
232     snew(tab, 1);
233     add_reserved_symbols(tab);
234     add_position_symbols(tab);
235     *tabp = tab;
236     return 0;
237 }
238
239 /*!
240  * \param[in] tab Symbol table to free.
241  *
242  * The pointer \p tab is invalid after the call.
243  */
244 void
245 _gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
246 {
247     gmx_sel_symrec_t *sym;
248
249     while (tab->first)
250     {
251         sym = tab->first;
252         tab->first = sym->next;
253         if (sym->type == SYMBOL_VARIABLE)
254         {
255             _gmx_selelem_free(sym->u.var);
256         }
257         sfree(sym->name);
258         sfree(sym);
259     }
260     sfree(tab);
261 }
262
263 /*!
264  * \param[in] tab    Symbol table to search.
265  * \param[in] name   Symbol name to find.
266  * \param[in] bExact If false, symbols that begin with \p name are also
267  *   considered.
268  * \returns   Pointer to the symbol with name \p name, or NULL if not found.
269  *
270  * If no exact match is found and \p bExact is false, returns a symbol that
271  * begins with \p name if a unique matching symbol is found.
272  */
273 gmx_sel_symrec_t *
274 _gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, bool bExact)
275 {
276     return _gmx_sel_find_symbol_len(tab, name, strlen(name), bExact);
277 }
278
279 /*!
280  * \param[in] tab    Symbol table to search.
281  * \param[in] name   Symbol name to find.
282  * \param[in] len    Only consider the first \p len characters of \p name.
283  * \param[in] bExact If false, symbols that begin with \p name are also
284  *   considered.
285  * \returns   Pointer to the symbol with name \p name, or NULL if not found.
286  *
287  * If no exact match is found and \p bExact is false, returns a symbol that
288  * begins with \p name if a unique matching symbol is found.
289  *
290  * The parameter \p len is there to allow using this function from scanner.l
291  * without modifying the text to be scanned or copying it.
292  */
293 gmx_sel_symrec_t *
294 _gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
295                          bool bExact)
296 {
297     gmx_sel_symrec_t *sym;
298     gmx_sel_symrec_t *match;
299     bool              bUnique;
300     bool              bMatch;
301
302     match = NULL;
303     bUnique = true;
304     bMatch  = false;
305     sym = tab->first;
306     while (sym)
307     {
308         if (!strncmp(sym->name, name, len))
309         {
310             if (strlen(sym->name) == len)
311             {
312                 return sym;
313             }
314             if (bMatch)
315             {
316                 bUnique = false;
317             }
318             bMatch = true;
319             if (sym->type == SYMBOL_METHOD)
320             {
321                 match = sym;
322             }
323         }
324         sym = sym->next;
325     }
326     if (bExact)
327     {
328         return NULL;
329     }
330
331     if (!bUnique)
332     {
333         fprintf(stderr, "parse error: ambiguous symbol\n");
334         return NULL;
335     }
336     return match;
337 }
338
339 /*!
340  * \param[in] tab   Symbol table to search.
341  * \param[in] type  Type of symbol to find.
342  * \returns   The first symbol in \p tab with type \p type,
343  *   or NULL if there are no such symbols.
344  */
345 gmx_sel_symrec_t *
346 _gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type)
347 {
348     gmx_sel_symrec_t *sym;
349
350     sym = tab->first;
351     while (sym)
352     {
353         if (sym->type == type)
354         {
355             return sym;
356         }
357         sym = sym->next;
358     }
359     return NULL;
360 }
361
362 /*!
363  * \param[in] after Start the search after this symbol.
364  * \param[in] type  Type of symbol to find.
365  * \returns   The next symbol after \p after with type \p type,
366  *   or NULL if there are no more symbols.
367  */
368 gmx_sel_symrec_t *
369 _gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type)
370 {
371     gmx_sel_symrec_t *sym;
372
373     sym = after->next;
374     while (sym)
375     {
376         if (sym->type == type)
377         {
378             return sym;
379         }
380         sym = sym->next;
381     }
382     return NULL;
383 }
384
385 /*! \brief
386  * Internal utility function used in adding symbols to a symbol table.
387  *
388  * \param[in,out] tab   Symbol table to add the symbol to.
389  * \param[in]     name  Name of the symbol to add.
390  * \param[out]    ctype On error, the type of the conflicting symbol is
391  *   written to \p *ctype.
392  * \returns       Pointer to the new symbol record, or NULL if \p name
393  *   conflicts with an existing symbol.
394  */
395 static gmx_sel_symrec_t *
396 add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
397 {
398     gmx_sel_symrec_t *sym, *psym;
399     int               len;
400
401     /* Check if there is a conflicting symbol */
402     psym = NULL;
403     sym  = tab->first;
404     while (sym)
405     {
406         if (!gmx_strcasecmp(sym->name, name))
407         {
408             *ctype = sym->type;
409             return NULL;
410         }
411         psym = sym;
412         sym  = sym->next;
413     }
414
415     /* Create a new symbol record */
416     if (psym == NULL)
417     {
418         snew(tab->first, 1);
419         sym = tab->first;
420     }
421     else
422     {
423         snew(psym->next, 1);
424         sym = psym->next;
425     }
426     sym->name = strdup(name);
427     return sym;
428 }
429
430 /*!
431  * \param[in,out] tab    Symbol table to add the symbol to.
432  * \param[in]     name   Name of the new symbol.
433  * \param[in]     sel    Value of the variable.
434  * \returns       Pointer to the created symbol record, or NULL if there was a
435  *   symbol with the same name.
436  */
437 gmx_sel_symrec_t *
438 _gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
439                         struct t_selelem *sel)
440 {
441     gmx_sel_symrec_t *sym;
442     e_symbol_t        ctype;
443
444     sym = add_symbol(tab, name, &ctype);
445     if (!sym)
446     {
447         fprintf(stderr, "parse error: ");
448         switch (ctype)
449         {
450             case SYMBOL_RESERVED:
451             case SYMBOL_POS:
452                 fprintf(stderr, "variable name (%s) conflicts with a reserved keyword\n",
453                         name);
454                 break;
455             case SYMBOL_VARIABLE:
456                 fprintf(stderr, "duplicate variable name (%s)\n", name);
457                 break;
458             case SYMBOL_METHOD:
459                 fprintf(stderr, "variable name (%s) conflicts with a selection keyword\n",
460                         name);
461                 break;
462         }
463         return NULL;
464     }
465
466     sym->type  = SYMBOL_VARIABLE;
467     sym->u.var = sel;
468     sel->refcount++;
469     return sym;
470 }
471
472 /*!
473  * \param[in,out] tab    Symbol table to add the symbol to.
474  * \param[in]     name   Name of the new symbol.
475  * \param[in]     method Method that this symbol represents.
476  * \returns       Pointer to the created symbol record, or NULL if there was a
477  *   symbol with the same name.
478  */
479 gmx_sel_symrec_t *
480 _gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
481                            struct gmx_ana_selmethod_t *method)
482 {
483     gmx_sel_symrec_t *sym;
484     e_symbol_t        ctype;
485
486     sym = add_symbol(tab, name, &ctype);
487     if (!sym)
488     {
489         fprintf(stderr, "parse error: ");
490         switch (ctype)
491         {
492             case SYMBOL_RESERVED:
493             case SYMBOL_POS:
494                 fprintf(stderr, "method name (%s) conflicts with a reserved keyword\n",
495                         name);
496                 break;
497             case SYMBOL_VARIABLE:
498                 fprintf(stderr, "method name (%s) conflicts with a variable name\n",
499                         name);
500                 break;
501             case SYMBOL_METHOD:
502                 fprintf(stderr, "duplicate method name (%s)\n", name);
503                 break;
504         }
505         return NULL;
506     }
507
508     sym->type   = SYMBOL_METHOD;
509     sym->u.meth = method;
510     return sym;
511 }