Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / gmxlib / selection / symrec.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2009, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 /*! \internal \file
39  * \brief Implementation of functions in symrec.h.
40  */
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 #include <macros.h>
46 #include <smalloc.h>
47 #include <string2.h>
48 #include <typedefs.h>
49 #include <gmx_fatal.h>
50
51 #include <poscalc.h>
52
53 #include "selelem.h"
54 #include "symrec.h"
55
56 /*! \internal \brief
57  * Symbol table for the selection parser.
58  */
59 struct gmx_sel_symtab_t
60 {
61     /** Pointer to the first symbol in the linked list of symbols. */
62     gmx_sel_symrec_t *first;
63 };
64
65 /*! \internal \brief
66  * Single symbol for the selection parser.
67  */
68 struct gmx_sel_symrec_t
69 {
70     /** Name of the symbol. */
71     char                           *name;
72     /** Type of the symbol. */
73     e_symbol_t                      type;
74     /** Value of the symbol. */
75     union {
76         /** Pointer to the method structure (\ref SYMBOL_METHOD). */
77         struct gmx_ana_selmethod_t *meth;
78         /** Pointer to the variable value (\ref SYMBOL_VARIABLE). */
79         struct t_selelem           *var;
80     }                               u;
81     /** Pointer to the next symbol. */
82     struct gmx_sel_symrec_t        *next;
83 };
84
85 /** List of reserved symbols to register in add_reserved_symbols(). */
86 static const char *const sym_reserved[] = {
87     "group",
88     "to",
89     "not",
90     "and",
91     "or",
92     "xor",
93     "yes",
94     "no",
95     "on",
96     "off",
97     "help",
98 };
99
100 /*!
101  * \param[in] sym Symbol to query.
102  * \returns   The name of \p sym.
103  *
104  * The returned pointer should not be free'd.
105  */
106 char *
107 _gmx_sel_sym_name(gmx_sel_symrec_t *sym)
108 {
109     return sym->name;
110 }
111
112 /*!
113  * \param[in] sym Symbol to query.
114  * \returns   The type of \p sym.
115  */
116 e_symbol_t
117 _gmx_sel_sym_type(gmx_sel_symrec_t *sym)
118 {
119     return sym->type;
120 }
121
122 /*!
123  * \param[in] sym Symbol to query.
124  * \returns   The method associated with \p sym, or NULL if \p sym is not a
125  *   \ref SYMBOL_METHOD symbol.
126  */
127 struct gmx_ana_selmethod_t *
128 _gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
129 {
130     if (sym->type != SYMBOL_METHOD)
131     {
132         gmx_call("symbol is not a method symbol");
133         return NULL;
134     }
135     return sym->u.meth;
136 }
137
138 /*!
139  * \param[in] sym Symbol to query.
140  * \returns   The variable expression associated with \p sym, or NULL if
141  *   \p sym is not a \ref SYMBOL_VARIABLE symbol.
142  */
143 struct t_selelem *
144 _gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
145 {
146     if (sym->type != SYMBOL_VARIABLE)
147     {
148         gmx_call("symbol is not a variable symbol");
149         return NULL;
150     }
151     return sym->u.var;
152 }
153
154 /*! \brief
155  * Adds the reserved symbols to a symbol table.
156  * 
157  * \param[in,out] tab  Symbol table to which the symbols are added.
158  *
159  * Assumes that the symbol table is empty.
160  */
161 static void
162 add_reserved_symbols(gmx_sel_symtab_t *tab)
163 {
164     gmx_sel_symrec_t *sym;
165     gmx_sel_symrec_t *last;
166     size_t            i;
167
168     last = NULL;
169     for (i = 0; i < asize(sym_reserved); ++i)
170     {
171         snew(sym, 1);
172         sym->name = strdup(sym_reserved[i]);
173         sym->type = SYMBOL_RESERVED;
174         sym->next = NULL;
175         if (last)
176         {
177             last->next = sym;
178         }
179         else
180         {
181             tab->first = sym;
182         }
183         last = sym;
184     }
185 }
186
187 /*! \brief
188  * Adds the position symbols to the symbol list.
189  * 
190  * \param[in,out] tab  Symbol table to which the symbols are added.
191  */
192 static void
193 add_position_symbols(gmx_sel_symtab_t *tab)
194 {
195     const char       **postypes;
196     gmx_sel_symrec_t  *sym;
197     gmx_sel_symrec_t  *last;
198     int                i;
199
200     postypes = gmx_ana_poscalc_create_type_enum(TRUE);
201     last = tab->first;
202     while (last && last->next)
203     {
204         last = last->next;
205     }
206     for (i = 1; postypes[i] != NULL; ++i)
207     {
208         snew(sym, 1);
209         sym->name = strdup(postypes[i]);
210         sym->type = SYMBOL_POS;
211         sym->next = NULL;
212         if (last)
213         {
214             last->next = sym;
215         }
216         else
217         {
218             tab->first = sym;
219         }
220         last = sym;
221     }
222     sfree(postypes);
223 }
224
225 /*!
226  * \param[out] tabp Symbol table pointer to initialize.
227  *
228  * Reserved and position symbols are added to the created table.
229  */
230 int
231 _gmx_sel_symtab_create(gmx_sel_symtab_t **tabp)
232 {
233     gmx_sel_symtab_t *tab;
234
235     snew(tab, 1);
236     add_reserved_symbols(tab);
237     add_position_symbols(tab);
238     *tabp = tab;
239     return 0;
240 }
241
242 /*!
243  * \param[in] tab Symbol table to free.
244  *
245  * The pointer \p tab is invalid after the call.
246  */
247 void
248 _gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
249 {
250     gmx_sel_symrec_t *sym;
251
252     while (tab->first)
253     {
254         sym = tab->first;
255         tab->first = sym->next;
256         if (sym->type == SYMBOL_VARIABLE)
257         {
258             _gmx_selelem_free(sym->u.var);
259         }
260         sfree(sym->name);
261         sfree(sym);
262     }
263     sfree(tab);
264 }
265
266 /*!
267  * \param[in] tab    Symbol table to search.
268  * \param[in] name   Symbol name to find.
269  * \param[in] bExact If FALSE, symbols that begin with \p name are also
270  *   considered.
271  * \returns   Pointer to the symbol with name \p name, or NULL if not found.
272  *
273  * If no exact match is found and \p bExact is FALSE, returns a symbol that
274  * begins with \p name if a unique matching symbol is found.
275  */
276 gmx_sel_symrec_t *
277 _gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, gmx_bool bExact)
278 {
279     return _gmx_sel_find_symbol_len(tab, name, strlen(name), bExact);
280 }
281
282 /*!
283  * \param[in] tab    Symbol table to search.
284  * \param[in] name   Symbol name to find.
285  * \param[in] len    Only consider the first \p len characters of \p name.
286  * \param[in] bExact If FALSE, symbols that begin with \p name are also
287  *   considered.
288  * \returns   Pointer to the symbol with name \p name, or NULL if not found.
289  *
290  * If no exact match is found and \p bExact is FALSE, returns a symbol that
291  * begins with \p name if a unique matching symbol is found.
292  *
293  * The parameter \p len is there to allow using this function from scanner.l
294  * without modifying the text to be scanned or copying it.
295  */
296 gmx_sel_symrec_t *
297 _gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
298                          gmx_bool bExact)
299 {
300     gmx_sel_symrec_t *sym;
301     gmx_sel_symrec_t *match;
302     gmx_bool              bUnique;
303     gmx_bool              bMatch;
304
305     match = NULL;
306     bUnique = TRUE;
307     bMatch  = FALSE;
308     sym = tab->first;
309     while (sym)
310     {
311         if (!strncmp(sym->name, name, len))
312         {
313             if (strlen(sym->name) == len)
314             {
315                 return sym;
316             }
317             if (bMatch)
318             {
319                 bUnique = FALSE;
320             }
321             bMatch = TRUE;
322             if (sym->type == SYMBOL_METHOD)
323             {
324                 match = sym;
325             }
326         }
327         sym = sym->next;
328     }
329     if (bExact)
330     {
331         return NULL;
332     }
333
334     if (!bUnique)
335     {
336         fprintf(stderr, "parse error: ambiguous symbol\n");
337         return NULL;
338     }
339     return match;
340 }
341
342 /*!
343  * \param[in] tab   Symbol table to search.
344  * \param[in] type  Type of symbol to find.
345  * \returns   The first symbol in \p tab with type \p type,
346  *   or NULL if there are no such symbols.
347  */
348 gmx_sel_symrec_t *
349 _gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type)
350 {
351     gmx_sel_symrec_t *sym;
352
353     sym = tab->first;
354     while (sym)
355     {
356         if (sym->type == type)
357         {
358             return sym;
359         }
360         sym = sym->next;
361     }
362     return NULL;
363 }
364
365 /*!
366  * \param[in] after Start the search after this symbol.
367  * \param[in] type  Type of symbol to find.
368  * \returns   The next symbol after \p after with type \p type,
369  *   or NULL if there are no more symbols.
370  */
371 gmx_sel_symrec_t *
372 _gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type)
373 {
374     gmx_sel_symrec_t *sym;
375
376     sym = after->next;
377     while (sym)
378     {
379         if (sym->type == type)
380         {
381             return sym;
382         }
383         sym = sym->next;
384     }
385     return NULL;
386 }
387
388 /*! \brief
389  * Internal utility function used in adding symbols to a symbol table.
390  *
391  * \param[in,out] tab   Symbol table to add the symbol to.
392  * \param[in]     name  Name of the symbol to add.
393  * \param[out]    ctype On error, the type of the conflicting symbol is
394  *   written to \p *ctype.
395  * \returns       Pointer to the new symbol record, or NULL if \p name
396  *   conflicts with an existing symbol.
397  */
398 static gmx_sel_symrec_t *
399 add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
400 {
401     gmx_sel_symrec_t *sym, *psym;
402     int               len;
403
404     /* Check if there is a conflicting symbol */
405     psym = NULL;
406     sym  = tab->first;
407     while (sym)
408     {
409         if (!gmx_strcasecmp(sym->name, name))
410         {
411             *ctype = sym->type;
412             return NULL;
413         }
414         psym = sym;
415         sym  = sym->next;
416     }
417
418     /* Create a new symbol record */
419     if (psym == NULL)
420     {
421         snew(tab->first, 1);
422         sym = tab->first;
423     }
424     else
425     {
426         snew(psym->next, 1);
427         sym = psym->next;
428     }
429     sym->name = strdup(name);
430     return sym;
431 }
432
433 /*!
434  * \param[in,out] tab    Symbol table to add the symbol to.
435  * \param[in]     name   Name of the new symbol.
436  * \param[in]     sel    Value of the variable.
437  * \returns       Pointer to the created symbol record, or NULL if there was a
438  *   symbol with the same name.
439  */
440 gmx_sel_symrec_t *
441 _gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
442                         struct t_selelem *sel)
443 {
444     gmx_sel_symrec_t *sym;
445     e_symbol_t        ctype;
446
447     sym = add_symbol(tab, name, &ctype);
448     if (!sym)
449     {
450         fprintf(stderr, "parse error: ");
451         switch (ctype)
452         {
453             case SYMBOL_RESERVED:
454             case SYMBOL_POS:
455                 fprintf(stderr, "variable name (%s) conflicts with a reserved keyword\n",
456                         name);
457                 break;
458             case SYMBOL_VARIABLE:
459                 fprintf(stderr, "duplicate variable name (%s)\n", name);
460                 break;
461             case SYMBOL_METHOD:
462                 fprintf(stderr, "variable name (%s) conflicts with a selection keyword\n",
463                         name);
464                 break;
465         }
466         return NULL;
467     }
468
469     sym->type  = SYMBOL_VARIABLE;
470     sym->u.var = sel;
471     sel->refcount++;
472     return sym;
473 }
474
475 /*!
476  * \param[in,out] tab    Symbol table to add the symbol to.
477  * \param[in]     name   Name of the new symbol.
478  * \param[in]     method Method that this symbol represents.
479  * \returns       Pointer to the created symbol record, or NULL if there was a
480  *   symbol with the same name.
481  */
482 gmx_sel_symrec_t *
483 _gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
484                            struct gmx_ana_selmethod_t *method)
485 {
486     gmx_sel_symrec_t *sym;
487     e_symbol_t        ctype;
488
489     sym = add_symbol(tab, name, &ctype);
490     if (!sym)
491     {
492         fprintf(stderr, "parse error: ");
493         switch (ctype)
494         {
495             case SYMBOL_RESERVED:
496             case SYMBOL_POS:
497                 fprintf(stderr, "method name (%s) conflicts with a reserved keyword\n",
498                         name);
499                 break;
500             case SYMBOL_VARIABLE:
501                 fprintf(stderr, "method name (%s) conflicts with a variable name\n",
502                         name);
503                 break;
504             case SYMBOL_METHOD:
505                 fprintf(stderr, "duplicate method name (%s)\n", name);
506                 break;
507         }
508         return NULL;
509     }
510
511     sym->type   = SYMBOL_METHOD;
512     sym->u.meth = method;
513     return sym;
514 }