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