3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
29 * For more info, check our website at http://www.gromacs.org
31 /*! \cond \internal \file scanner.l
33 * Tokenizer for the selection language.
36 /*! \internal \file scanner.c
38 * Generated (from scanner.l by Flex) tokenizer for the selection language.
50 #include <selmethod.h>
52 #include "parsetree.h"
53 #include "selcollection.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;
78 gmx_ana_selmethod_t **mstack;
82 gmx_ana_selparam_t *nextparam;
88 YY_BUFFER_STATE buffer;
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... */
96 process_next_param(YYSTYPE *, gmx_sel_lexer_t *state);
98 process_identifier(YYSTYPE *, char *, int,
99 gmx_sel_lexer_t *state);
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) \
107 gmx_sel_lexer_t *state = yyget_extra(yyscanner); \
109 if (state->bPrompt) \
111 fprintf(stderr, "%s ", state->prompt); \
112 state->bPrompt = FALSE; \
114 for (n = 0; n < max_size && \
115 (c = getc(yyin)) != EOF && c != '\n'; ++n) \
121 buf[n++] = (char)c; \
124 state->prompt = DEFAULT_PROMPT; \
125 state->bPrompt = TRUE; \
128 if (c == EOF && ferror(yyin)) \
130 YY_FATAL_ERROR("input in flex scanner failed"); \
133 if (state->strstore) \
135 while (n > state->nalloc_str - state->slen) \
137 state->nalloc_str += STRSTORE_ALLOCSTEP; \
138 srenew(*state->strstore, state->nalloc_str); \
140 strncpy((*state->strstore)+state->slen, buf, n); \
142 if (state->nalloc_str > 0) \
144 (*state->strstore)[state->slen] = 0; \
152 FRAC (([[:digit:]]*"."{DSEQ})|{DSEQ}".")
153 EXP ([eE][+-]?{DSEQ})
154 REAL ("-"?(({FRAC}{EXP}?)|({DSEQ}{EXP})))
155 STRING (\"([^\"\\\n]|(\\\"))*\")
156 IDENTIFIER ([[:alpha:]][_[:alnum:]]*)
157 CMPOP (([<>]=?)|([!=]=))
163 %option prefix="_gmx_sel_yy"
172 gmx_sel_lexer_t *state = yyget_extra(yyscanner);
173 /* Return END_OF_METHOD/PARAM_* immediately if necessary */
174 if (state->nextparam)
176 return process_next_param(yylval, state);
178 /* Handle the start conditions for 'of' matching */
182 state->bMatchOf = FALSE;
184 else if (state->bCmdStart)
187 state->bCmdStart = FALSE;
189 else if (YYSTATE != help)
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; }
202 if (yytext[0] == ';' || state->prompt)
204 state->bCmdStart = TRUE;
208 <cmdstart>help { BEGIN(help); return HELP; }
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
233 * There are other ways of doing this, but this is probably the easiest. */
239 process_next_param(YYSTYPE *yylval, gmx_sel_lexer_t *state)
241 gmx_ana_selparam_t *param = state->nextparam;
246 return END_OF_METHOD;
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)
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;
261 return INVALID; /* Should not be reached */
265 process_identifier(YYSTYPE *yylval, char *yytext, int yyleng,
266 gmx_sel_lexer_t *state)
268 gmx_sel_symrec_t *symbol;
271 /* Check if the identifier matches with a parameter name */
274 gmx_ana_selparam_t *param = NULL;
276 while (!param && sp >= 0)
279 for (i = 0; i < state->mstack[sp]->nparams; ++i)
281 if (state->mstack[sp]->param[i].name == NULL)
285 if (!strncmp(state->mstack[sp]->param[i].name, yytext, yyleng))
287 param = &state->mstack[sp]->param[i];
300 state->neom = state->msp - sp - 1;
301 state->nextparam = param;
302 return END_OF_METHOD;
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)
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;
316 return INVALID; /* Should not be reached */
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 */
325 yylval->str = strndup(yytext, yyleng);
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)
336 /* For variable symbols, return the type of the variable value */
337 if (symtype == SYMBOL_VARIABLE)
341 var = _gmx_sel_sym_value_var(symbol);
342 /* Return simple tokens for constant variables */
343 if (var->type == SEL_CONST)
348 yylval->i = var->v.u.i[0];
351 yylval->r = var->v.u.r[0];
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;
370 /* For method symbols, return the correct type */
371 if (symtype == SYMBOL_METHOD)
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)
380 switch (method->type)
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;
389 /* Method with parameters or a modifier */
390 if (method->flags & SMETH_MODIFIER)
392 /* Remove all methods from the stack */
394 if (method->param[1].name == NULL)
396 state->nextparam = &method->param[1];
401 if (method->param[0].name == NULL)
403 state->nextparam = &method->param[0];
407 if (state->msp >= state->mstack_alloc)
409 state->mstack_alloc += 10;
410 srenew(state->mstack, state->mstack_alloc);
412 state->mstack[state->msp] = method;
413 if (method->flags & SMETH_MODIFIER)
417 switch (method->type)
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;
429 /* For position symbols, we need to return KEYWORD_POS, but we also need
430 * some additional handling. */
431 if (symtype == SYMBOL_POS)
433 state->bMatchOf = TRUE;
434 yylval->str = _gmx_sel_sym_name(symbol);
437 /* Should not be reached */
442 add_token(const char *str, int len, gmx_sel_lexer_t *state)
444 if (!str || len == 0 || strlen(str) == 0)
452 /* Allocate more memory if necessary */
453 if (state->nalloc_psel - state->pslen < len)
455 int incr = STRSTORE_ALLOCSTEP < len ? len : STRSTORE_ALLOCSTEP;
456 state->nalloc_psel += incr;
457 srenew(state->pselstr, state->nalloc_psel);
459 /* Append the token to the stored string */
460 strncpy(state->pselstr + state->pslen, str, len);
462 state->pselstr[state->pslen] = 0;
466 _gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
469 gmx_sel_lexer_t *state;
472 rc = yylex_init(scannerp);
480 state->bPrompt = bInteractive;
481 state->prompt = bInteractive ? DEFAULT_PROMPT : NULL;
483 state->strstore = &sc->selstr;
486 state->slen = strlen(sc->selstr);
487 state->nalloc_str = state->slen + 1;
492 state->nalloc_str = 0;
495 snew(state->pselstr, STRSTORE_ALLOCSTEP);
496 state->pselstr[0] = 0;
498 state->nalloc_psel = STRSTORE_ALLOCSTEP;
500 snew(state->mstack, 20);
501 state->mstack_alloc = 20;
504 state->nextparam = NULL;
505 state->bMatchOf = FALSE;
506 state->bCmdStart = TRUE;
507 state->bBuffer = FALSE;
509 yyset_extra(state, *scannerp);
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);
522 yy_delete_buffer(state->buffer, scanner);
525 yylex_destroy(scanner);
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);
543 _gmx_sel_lexer_pselstr(yyscan_t scanner)
545 gmx_sel_lexer_t *state = yyget_extra(scanner);
546 return state->pselstr;
550 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner)
552 gmx_sel_lexer_t *state = yyget_extra(scanner);
553 state->pselstr[0] = 0;
558 _gmx_sel_finish_method(yyscan_t scanner)
560 gmx_sel_lexer_t *state = yyget_extra(scanner);
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);
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 */
590 if (*state->strstore)
592 slen = strlen(*state->strstore);
599 snew(*state->strstore, len + slen + 1);
600 strcpy((*state->strstore)+slen, str);