Framework for printing help for selections.
[gromacs/adressmacs.git] / src / gmxlib / selection / scanner.l
blob70e70b56ec6b61a984e1506394c863c6e3714bf5
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.
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 /*! \cond \internal \file scanner.l
32  * \brief
33  * Tokenizer for the selection language.
34  * \endcond
35  */
36 /*! \internal \file scanner.c
37  * \brief
38  * Generated (from scanner.l by Flex) tokenizer for the selection language.
39  */
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
45 #include <math.h>
47 #include <smalloc.h>
48 #include <string2.h>
50 #include <selmethod.h>
52 #include "parsetree.h"
53 #include "selcollection.h"
54 #include "selelem.h"
55 #include "symrec.h"
57 #include "parser.h"
58 #include "scanner.h"
60 #define DEFAULT_PROMPT     ">"
61 #define CONTINUE_PROMPT    "..."
62 #define STRSTORE_ALLOCSTEP 1000
64 typedef struct gmx_sel_lexer_t
66     struct gmx_ana_selcollection_t *sc;
67     bool                  bPrompt;
68     const char           *prompt;
70     char                **strstore;
71     int                   slen;
72     int                   nalloc_str;
74     char                 *pselstr;
75     int                   pslen;
76     int                   nalloc_psel;
78     gmx_ana_selmethod_t **mstack;
79     int                   msp;
80     int                   mstack_alloc;
81     int                   neom;
82     gmx_ana_selparam_t   *nextparam;
84     bool                  bMatchOf;
85     bool                  bCmdStart;
87     bool                  bBuffer;
88     YY_BUFFER_STATE       buffer;
89 } gmx_sel_lexer_t;
91 #define YY_EXTRA_TYPE gmx_sel_lexer_t *
93 /* Because Flex defines yylval, yytext, and yyleng as macros,
94  * we cannot have them here as parameter names... */
95 static int
96 process_next_param(YYSTYPE *, gmx_sel_lexer_t *state);
97 static int
98 process_identifier(YYSTYPE *, char *, int,
99                    gmx_sel_lexer_t *state);
100 static void
101 add_token(const char *str, int len, gmx_sel_lexer_t *state);
103 #define ADD_TOKEN add_token(yytext, yyleng, state)
105 #define YY_INPUT(buf,result,max_size) \
106     { \
107         gmx_sel_lexer_t *state = yyget_extra(yyscanner); \
108         int c = '*', n; \
109         if (state->bPrompt) \
110         { \
111             fprintf(stderr, "%s ", state->prompt); \
112             state->bPrompt = FALSE; \
113         } \
114         for (n = 0; n < max_size && \
115                     (c = getc(yyin)) != EOF && c != '\n'; ++n) \
116         { \
117             buf[n] = (char)c; \
118         } \
119         if (c == '\n') \
120         { \
121             buf[n++] = (char)c; \
122             if (state->prompt) \
123             { \
124                 state->prompt  = DEFAULT_PROMPT; \
125                 state->bPrompt = TRUE; \
126             } \
127         } \
128         if (c == EOF && ferror(yyin)) \
129         { \
130             YY_FATAL_ERROR("input in flex scanner failed"); \
131         } \
132         result = n; \
133         if (state->strstore) \
134         { \
135             while (n > state->nalloc_str - state->slen) \
136             { \
137                 state->nalloc_str += STRSTORE_ALLOCSTEP; \
138                 srenew(*state->strstore, state->nalloc_str); \
139             } \
140             strncpy((*state->strstore)+state->slen, buf, n); \
141             state->slen += n; \
142             if (state->nalloc_str > 0) \
143             { \
144                 (*state->strstore)[state->slen] = 0; \
145             } \
146         } \
147     }
150 INTEGER    [[:digit:]]+
151 DSEQ       ([[:digit:]]+)
152 FRAC       (([[:digit:]]*"."{DSEQ})|{DSEQ}".")
153 EXP        ([eE][+-]?{DSEQ})
154 REAL       ("-"?(({FRAC}{EXP}?)|({DSEQ}{EXP})))
155 STRING     (\"([^\"\\\n]|(\\\"))*\")
156 IDENTIFIER ([[:alpha:]][_[:alnum:]]*)
157 CMPOP      (([<>]=?)|([!=]=))
158 COMMENT    (#.*)
160 %option nodefault
161 %option noyywrap
162 %option reentrant
163 %option prefix="_gmx_sel_yy"
165 %s matchof
166 %s cmdstart
167 %x help
172     gmx_sel_lexer_t *state = yyget_extra(yyscanner);
173     /* Return END_OF_METHOD/PARAM_* immediately if necessary */
174     if (state->nextparam)
175     {
176         return process_next_param(yylval, state);
177     }
178     /* Handle the start conditions for 'of' matching */
179     if (state->bMatchOf)
180     {
181         BEGIN(matchof);
182         state->bMatchOf = FALSE;
183     }
184     else if (state->bCmdStart)
185     {
186         BEGIN(cmdstart);
187         state->bCmdStart = FALSE;
188     }
189     else if (YYSTATE != help)
190     {
191         BEGIN(0);
192     }
195 {COMMENT}
196 {INTEGER}       { yylval->i   = strtol(yytext, NULL, 10);    ADD_TOKEN; return INT;  }
197 {REAL}          { yylval->r   = strtod(yytext, NULL);        ADD_TOKEN; return REAL; }
198 {STRING}        { yylval->str = strndup(yytext+1, yyleng-2); ADD_TOKEN; return STR;  }
200 \\\n            { if (state->prompt) state->prompt = CONTINUE_PROMPT; }
201 ";"|\n          {
202                     if (yytext[0] == ';' || state->prompt)
203                     {
204                         state->bCmdStart = TRUE;
205                         return CMD_SEP;
206                     }
207                 }
208 <cmdstart>help  { BEGIN(help); return HELP; }
209 <help>{
210 [[:blank:]]+
211 {IDENTIFIER}    { yylval->str = strndup(yytext, yyleng); return HELP_TOPIC; }
212 ";"|\n          { state->bCmdStart = TRUE; return CMD_SEP; }
213 .               { return INVALID; }
215 group           { ADD_TOKEN; return GROUP; }
216 to              { ADD_TOKEN; return TO; }
217 <matchof>of     { ADD_TOKEN; BEGIN(0); return OF; }
218 and|"&&"        { ADD_TOKEN; return AND; }
219 or|"||"         { ADD_TOKEN; return OR; }
220 xor             { ADD_TOKEN; return XOR; }
221 not|"!"         { ADD_TOKEN; return NOT; }
222 {CMPOP}         { yylval->str = strndup(yytext, yyleng); ADD_TOKEN; return CMP_OP; }
224 {IDENTIFIER}    { return process_identifier(yylval, yytext, yyleng, state); }
226 [[:blank:]]+    { add_token(" ", 1, state); }
227 [_[:alnum:]]+   { yylval->str = strndup(yytext, yyleng); ADD_TOKEN; return STR; }
228 .               { add_token(yytext, 1, state); return yytext[0]; }
231 /* Undefine the macros so that we can have them as variable names in the
232  * subroutines.
233  * There are other ways of doing this, but this is probably the easiest. */
234 #undef yylval
235 #undef yytext
236 #undef yyleng
238 static int
239 process_next_param(YYSTYPE *yylval, gmx_sel_lexer_t *state)
241     gmx_ana_selparam_t *param = state->nextparam;
243     if (state->neom > 0)
244     {
245         --state->neom;
246         return END_OF_METHOD;
247     }
248     state->nextparam = NULL;
249     /* FIXME: The constness should not be cast away */
250     yylval->str = (char *)param->name;
251     add_token(param->name, -1, state);
252     switch (param->val.type)
253     {
254         case NO_VALUE:    return PARAM_BOOL;
255         case INT_VALUE:   return PARAM_INT;
256         case REAL_VALUE:  return PARAM_REAL;
257         case STR_VALUE:   return PARAM_STR;
258         case POS_VALUE:   return PARAM_POS;
259         case GROUP_VALUE: return PARAM_GROUP;
260     }
261     return INVALID; /* Should not be reached */
264 static int
265 process_identifier(YYSTYPE *yylval, char *yytext, int yyleng,
266                    gmx_sel_lexer_t *state)
268     gmx_sel_symrec_t *symbol;
269     e_symbol_t        symtype;
271     /* Check if the identifier matches with a parameter name */
272     if (state->msp >= 0)
273     {
274         gmx_ana_selparam_t *param = NULL;
275         int                 sp = state->msp;
276         while (!param && sp >= 0)
277         {
278             int             i;
279             for (i = 0; i < state->mstack[sp]->nparams; ++i)
280             {
281                 if (state->mstack[sp]->param[i].name == NULL)
282                 {
283                     continue;
284                 }
285                 if (!strncmp(state->mstack[sp]->param[i].name, yytext, yyleng))
286                 {
287                     param = &state->mstack[sp]->param[i];
288                     break;
289                 }
290             }
291             if (!param)
292             {
293                 --sp;
294             }
295         }
296         if (param)
297         {
298             if (sp < state->msp)
299             {
300                 state->neom = state->msp - sp - 1;
301                 state->nextparam = param;
302                 return END_OF_METHOD;
303             }
304             /* FIXME: The constness should not be cast away */
305             yylval->str = (char *)param->name;
306             add_token(param->name, -1, state);
307             switch (param->val.type)
308             {
309                 case NO_VALUE:    return PARAM_BOOL;
310                 case INT_VALUE:   return PARAM_INT;
311                 case REAL_VALUE:  return PARAM_REAL;
312                 case STR_VALUE:   return PARAM_STR;
313                 case POS_VALUE:   return PARAM_POS;
314                 case GROUP_VALUE: return PARAM_GROUP;
315             }
316             return INVALID; /* Should not be reached */
317         }
318     }
320     /* Check if the identifier matches with a symbol */
321     symbol = _gmx_sel_find_symbol_len(state->sc->symtab, yytext, yyleng, FALSE);
322     /* If there is no match, return the token as a string */
323     if (!symbol)
324     {
325         yylval->str = strndup(yytext, yyleng);
326         ADD_TOKEN;
327         return IDENTIFIER;
328     }
329     add_token(_gmx_sel_sym_name(symbol), -1, state);
330     symtype = _gmx_sel_sym_type(symbol);
331     /* Reserved symbols should have been caught earlier */
332     if (symtype == SYMBOL_RESERVED)
333     {
334         return INVALID;
335     }
336     /* For variable symbols, return the type of the variable value */
337     if (symtype == SYMBOL_VARIABLE)
338     {
339         t_selelem *var;
341         var = _gmx_sel_sym_value_var(symbol);
342         /* Return simple tokens for constant variables */
343         if (var->type == SEL_CONST)
344         {
345             switch (var->v.type)
346             {
347                 case INT_VALUE:
348                     yylval->i = var->v.u.i[0];
349                     return INT;
350                 case REAL_VALUE:
351                     yylval->r = var->v.u.r[0];
352                     return REAL;
353                 case POS_VALUE:
354                     break;
355                 default:
356                     return INVALID;
357             }
358         }
359         yylval->sel = var;
360         switch (var->v.type)
361         {
362             case INT_VALUE:   return VARIABLE_NUMERIC;
363             case REAL_VALUE:  return VARIABLE_NUMERIC;
364             case POS_VALUE:   return VARIABLE_POS;
365             case GROUP_VALUE: return VARIABLE_GROUP;
366             default:          return INVALID;
367         }
368         return INVALID;
369     }
370     /* For method symbols, return the correct type */
371     if (symtype == SYMBOL_METHOD)
372     {
373         gmx_ana_selmethod_t *method;
375         method = _gmx_sel_sym_value_method(symbol);
376         yylval->meth = method;
377         if (!(method->flags & SMETH_MODIFIER) && method->nparams == 0)
378         {
379             /* Keyword */
380             switch (method->type)
381             {
382                 case INT_VALUE:   return KEYWORD_INT;
383                 case REAL_VALUE:  return KEYWORD_REAL;
384                 case STR_VALUE:   return KEYWORD_STR;
385                 case GROUP_VALUE: return KEYWORD_GROUP;
386                 default:          return INVALID;
387             }
388         } else {
389             /* Method with parameters or a modifier */
390             if (method->flags & SMETH_MODIFIER)
391             {
392                 /* Remove all methods from the stack */
393                 state->msp = -1;
394                 if (method->param[1].name == NULL)
395                 {
396                     state->nextparam = &method->param[1];
397                 }
398             }
399             else
400             {
401                 if (method->param[0].name == NULL)
402                 {
403                     state->nextparam = &method->param[0];
404                 }
405             }
406             ++state->msp;
407             if (state->msp >= state->mstack_alloc)
408             {
409                 state->mstack_alloc += 10;
410                 srenew(state->mstack, state->mstack_alloc);
411             }
412             state->mstack[state->msp] = method;
413             if (method->flags & SMETH_MODIFIER)
414             {
415                 return MODIFIER;
416             }
417             switch (method->type)
418             {
419                 case INT_VALUE:   return METHOD_NUMERIC;
420                 case REAL_VALUE:  return METHOD_NUMERIC;
421                 case POS_VALUE:   return METHOD_POS;
422                 case GROUP_VALUE: return METHOD_GROUP;
423                 default:
424                     --state->msp;
425                     return INVALID;
426             }
427         }
428     }
429     /* For position symbols, we need to return KEYWORD_POS, but we also need
430      * some additional handling. */
431     if (symtype == SYMBOL_POS)
432     {
433         state->bMatchOf = TRUE;
434         yylval->str = _gmx_sel_sym_name(symbol);
435         return KEYWORD_POS;
436     }
437     /* Should not be reached */
438     return INVALID;
441 static void
442 add_token(const char *str, int len, gmx_sel_lexer_t *state)
444     if (!str || len == 0 || strlen(str) == 0)
445     {
446         return;
447     }
448     if (len < 0)
449     {
450         len = strlen(str);
451     }
452     /* Allocate more memory if necessary */
453     if (state->nalloc_psel - state->pslen < len)
454     {
455         int incr = STRSTORE_ALLOCSTEP < len ? len : STRSTORE_ALLOCSTEP;
456         state->nalloc_psel += incr;
457         srenew(state->pselstr, state->nalloc_psel);
458     }
459     /* Append the token to the stored string */
460     strncpy(state->pselstr + state->pslen, str, len);
461     state->pslen += len;
462     state->pselstr[state->pslen] = 0;
466 _gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
467                     bool bInteractive)
469     gmx_sel_lexer_t *state;
470     int              rc;
472     rc = yylex_init(scannerp);
473     if (rc != 0)
474     {
475         return rc;
476     }
478     snew(state, 1);
479     state->sc        = sc;
480     state->bPrompt   = bInteractive;
481     state->prompt    = bInteractive ? DEFAULT_PROMPT : NULL;
483     state->strstore  = &sc->selstr;
484     if (sc->selstr)
485     {
486         state->slen       = strlen(sc->selstr);
487         state->nalloc_str = state->slen + 1;
488     }
489     else
490     {
491         state->slen       = 0;
492         state->nalloc_str = 0;
493     }
495     snew(state->pselstr, STRSTORE_ALLOCSTEP);
496     state->pselstr[0]   = 0;
497     state->pslen        = 0;
498     state->nalloc_psel  = STRSTORE_ALLOCSTEP;
500     snew(state->mstack, 20);
501     state->mstack_alloc = 20;
502     state->msp          = -1;
503     state->neom         = 0;
504     state->nextparam    = NULL;
505     state->bMatchOf     = FALSE;
506     state->bCmdStart    = TRUE;
507     state->bBuffer      = FALSE;
509     yyset_extra(state, *scannerp);
510     return 0;
513 void
514 _gmx_sel_free_lexer(yyscan_t scanner)
516     gmx_sel_lexer_t *state = yyget_extra(scanner);
518     sfree(state->pselstr);
519     sfree(state->mstack);
520     if (state->bBuffer)
521     {
522         yy_delete_buffer(state->buffer, scanner);
523     }
524     sfree(state);
525     yylex_destroy(scanner);
528 bool
529 _gmx_sel_is_lexer_interactive(yyscan_t scanner)
531     gmx_sel_lexer_t *state = yyget_extra(scanner);
532     return state->bPrompt;
535 struct gmx_ana_selcollection_t *
536 _gmx_sel_lexer_selcollection(yyscan_t scanner)
538     gmx_sel_lexer_t *state = yyget_extra(scanner);
539     return state->sc;
542 const char *
543 _gmx_sel_lexer_pselstr(yyscan_t scanner)
545     gmx_sel_lexer_t *state = yyget_extra(scanner);
546     return state->pselstr;
549 void
550 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner)
552     gmx_sel_lexer_t *state = yyget_extra(scanner);
553     state->pselstr[0] = 0;
554     state->pslen      = 0;
557 void
558 _gmx_sel_finish_method(yyscan_t scanner)
560     gmx_sel_lexer_t *state = yyget_extra(scanner);
562     if (state->msp >= 0)
563     {
564         --state->msp;
565     }
568 void
569 _gmx_sel_set_lex_input_file(yyscan_t scanner, FILE *fp)
571     gmx_sel_lexer_t *state = yyget_extra(scanner);
573     state->bBuffer = TRUE;
574     state->buffer  = yy_create_buffer(fp, YY_BUF_SIZE, scanner);
575     yy_switch_to_buffer(state->buffer, scanner);
578 void
579 _gmx_sel_set_lex_input_str(yyscan_t scanner, const char *str)
581     gmx_sel_lexer_t *state = yyget_extra(scanner);
583     state->bBuffer = TRUE;
584     state->buffer  = yy_scan_string(str, scanner);
585     /* Append the buffer to the string store as YY_INPUT is not called */
586     if (state->strstore)
587     {
588         int len, slen;
590         if (*state->strstore)
591         {
592             slen = strlen(*state->strstore);
593         }
594         else
595         {
596             slen = 0;
597         }
598         len = strlen(str);
599         snew(*state->strstore, len + slen + 1);
600         strcpy((*state->strstore)+slen, str);
601     }