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
32 * \brief Helper functions for the selection tokenizer.
34 * This file implements the functions in the headers scanner.h and
37 /*! \internal file scanner_flex.h
38 * \brief Generated (from scanner.l) header file by Flex.
40 * This file contains definitions of functions that are needed in
53 #include "gmx_fatal.h"
55 #include <selmethod.h>
57 #include "parsetree.h"
58 #include "selcollection.h"
64 #include "scanner_internal.h"
66 #define STRSTORE_ALLOCSTEP 1000
68 /* These are defined as macros in the generated scanner_flex.h.
69 * We undefine them here to have them as variable names in the subroutines.
70 * There are other ways of doing this, but this is probably the easiest. */
76 read_stdin_line(gmx_sel_lexer_t
*state
)
78 char *ptr
= state
->inputstr
;
79 int max_len
= state
->nalloc_input
;
86 if (state
->bInteractive
)
88 fprintf(stderr
, "> ");
90 while (fgets(ptr
, max_len
, stdin
))
92 int len
= strlen(ptr
);
95 if (len
>= 2 && ptr
[len
- 1] == '\n' && ptr
[len
- 2] == '\\')
97 if (state
->bInteractive
)
99 fprintf(stderr
, "... ");
102 else if (len
>= 1 && ptr
[len
- 1] == '\n')
106 else if (len
< max_len
- 1)
108 if (state
->bInteractive
)
110 fprintf(stderr
, "\n");
118 max_len
+= state
->nalloc_input
;
119 state
->nalloc_input
*= 2;
120 len
= ptr
- state
->inputstr
;
121 srenew(state
->inputstr
, state
->nalloc_input
);
122 ptr
= state
->inputstr
+ len
;
127 gmx_input("selection reading failed");
129 state
->bCmdStart
= totlen
> 0;
134 _gmx_sel_yyblex(YYSTYPE
*yylval
, yyscan_t yyscanner
)
136 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(yyscanner
);
139 if (!state
->bBuffer
&& !state
->inputstr
)
141 state
->nalloc_input
= 1024;
142 snew(state
->inputstr
, state
->nalloc_input
);
143 read_stdin_line(state
);
144 _gmx_sel_set_lex_input_str(yyscanner
, state
->inputstr
);
146 token
= _gmx_sel_yylex(yylval
, yyscanner
);
147 while (state
->inputstr
&& token
== 0 && read_stdin_line(state
))
149 _gmx_sel_set_lex_input_str(yyscanner
, state
->inputstr
);
150 token
= _gmx_sel_yylex(yylval
, yyscanner
);
156 init_param_token(YYSTYPE
*yylval
, gmx_ana_selparam_t
*param
, bool bBoolNo
)
160 snew(yylval
->str
, strlen(param
->name
) + 3);
161 yylval
->str
[0] = 'n';
162 yylval
->str
[1] = 'o';
163 strcpy(yylval
->str
+2, param
->name
);
167 yylval
->str
= param
->name
? strdup(param
->name
) : NULL
;
173 init_method_token(YYSTYPE
*yylval
, gmx_ana_selmethod_t
*method
, bool bPosMod
,
174 gmx_sel_lexer_t
*state
)
176 /* If the previous token was not KEYWORD_POS, return EMPTY_POSMOD
177 * before the actual method to work around a limitation in Bison. */
178 if (!bPosMod
&& method
->type
!= POS_VALUE
)
180 state
->nextmethod
= method
;
183 yylval
->meth
= method
;
184 if (!(method
->flags
& SMETH_MODIFIER
) && method
->nparams
== 0)
187 switch (method
->type
)
189 case INT_VALUE
: return KEYWORD_NUMERIC
;
190 case REAL_VALUE
: return KEYWORD_NUMERIC
;
191 case STR_VALUE
: return KEYWORD_STR
;
192 case GROUP_VALUE
: return KEYWORD_GROUP
;
193 default: return INVALID
;
196 /* Method with parameters or a modifier */
197 if (method
->flags
& SMETH_MODIFIER
)
199 /* Remove all methods from the stack */
201 if (method
->param
[1].name
== NULL
)
203 state
->nextparam
= &method
->param
[1];
208 if (method
->param
[0].name
== NULL
)
210 state
->nextparam
= &method
->param
[0];
214 if (state
->msp
>= state
->mstack_alloc
)
216 state
->mstack_alloc
+= 10;
217 srenew(state
->mstack
, state
->mstack_alloc
);
219 state
->mstack
[state
->msp
] = method
;
220 if (method
->flags
& SMETH_MODIFIER
)
224 switch (method
->type
)
226 case INT_VALUE
: return METHOD_NUMERIC
;
227 case REAL_VALUE
: return METHOD_NUMERIC
;
228 case POS_VALUE
: return METHOD_POS
;
229 case GROUP_VALUE
: return METHOD_GROUP
;
235 return INVALID
; /* Should not be reached */
239 _gmx_sel_lexer_process_pending(YYSTYPE
*yylval
, gmx_sel_lexer_t
*state
)
241 if (state
->nextparam
)
243 gmx_ana_selparam_t
*param
= state
->nextparam
;
244 bool bBoolNo
= state
->bBoolNo
;
249 return END_OF_METHOD
;
251 state
->nextparam
= NULL
;
252 state
->bBoolNo
= FALSE
;
253 _gmx_sel_lexer_add_token(param
->name
, -1, state
);
254 return init_param_token(yylval
, param
, bBoolNo
);
256 if (state
->prev_pos_kw
> 0)
258 --state
->prev_pos_kw
;
260 if (state
->nextmethod
)
262 gmx_ana_selmethod_t
*method
= state
->nextmethod
;
264 state
->nextmethod
= NULL
;
265 return init_method_token(yylval
, method
, TRUE
, state
);
271 _gmx_sel_lexer_process_identifier(YYSTYPE
*yylval
, char *yytext
, size_t yyleng
,
272 gmx_sel_lexer_t
*state
)
274 gmx_sel_symrec_t
*symbol
;
277 /* Check if the identifier matches with a parameter name */
280 gmx_ana_selparam_t
*param
= NULL
;
281 bool bBoolNo
= FALSE
;
283 while (!param
&& sp
>= 0)
286 for (i
= 0; i
< state
->mstack
[sp
]->nparams
; ++i
)
288 /* Skip NULL parameters and too long parameters */
289 if (state
->mstack
[sp
]->param
[i
].name
== NULL
290 || strlen(state
->mstack
[sp
]->param
[i
].name
) > yyleng
)
294 if (!strncmp(state
->mstack
[sp
]->param
[i
].name
, yytext
, yyleng
))
296 param
= &state
->mstack
[sp
]->param
[i
];
299 /* Check separately for a 'no' prefix on boolean parameters */
300 if (state
->mstack
[sp
]->param
[i
].val
.type
== NO_VALUE
301 && yyleng
> 2 && yytext
[0] == 'n' && yytext
[1] == 'o'
302 && !strncmp(state
->mstack
[sp
]->param
[i
].name
, yytext
+2, yyleng
-2))
304 param
= &state
->mstack
[sp
]->param
[i
];
316 if (param
->val
.type
== NO_VALUE
&& !bBoolNo
)
318 state
->bMatchBool
= TRUE
;
322 state
->neom
= state
->msp
- sp
- 1;
323 state
->nextparam
= param
;
324 state
->bBoolNo
= bBoolNo
;
325 return END_OF_METHOD
;
327 _gmx_sel_lexer_add_token(param
->name
, -1, state
);
328 return init_param_token(yylval
, param
, bBoolNo
);
332 /* Check if the identifier matches with a symbol */
333 symbol
= _gmx_sel_find_symbol_len(state
->sc
->symtab
, yytext
, yyleng
, FALSE
);
334 /* If there is no match, return the token as a string */
337 yylval
->str
= strndup(yytext
, yyleng
);
338 _gmx_sel_lexer_add_token(yytext
, yyleng
, state
);
341 _gmx_sel_lexer_add_token(_gmx_sel_sym_name(symbol
), -1, state
);
342 symtype
= _gmx_sel_sym_type(symbol
);
343 /* Reserved symbols should have been caught earlier */
344 if (symtype
== SYMBOL_RESERVED
)
348 /* For variable symbols, return the type of the variable value */
349 if (symtype
== SYMBOL_VARIABLE
)
353 var
= _gmx_sel_sym_value_var(symbol
);
354 /* Return simple tokens for constant variables */
355 if (var
->type
== SEL_CONST
)
360 yylval
->i
= var
->v
.u
.i
[0];
363 yylval
->r
= var
->v
.u
.r
[0];
374 case INT_VALUE
: return VARIABLE_NUMERIC
;
375 case REAL_VALUE
: return VARIABLE_NUMERIC
;
376 case POS_VALUE
: return VARIABLE_POS
;
377 case GROUP_VALUE
: return VARIABLE_GROUP
;
378 default: return INVALID
;
382 /* For method symbols, return the correct type */
383 if (symtype
== SYMBOL_METHOD
)
385 gmx_ana_selmethod_t
*method
;
387 method
= _gmx_sel_sym_value_method(symbol
);
388 return init_method_token(yylval
, method
, state
->prev_pos_kw
> 0, state
);
390 /* For position symbols, we need to return KEYWORD_POS, but we also need
391 * some additional handling. */
392 if (symtype
== SYMBOL_POS
)
394 state
->bMatchOf
= TRUE
;
395 yylval
->str
= _gmx_sel_sym_name(symbol
);
396 state
->prev_pos_kw
= 2;
399 /* Should not be reached */
404 _gmx_sel_lexer_add_token(const char *str
, int len
, gmx_sel_lexer_t
*state
)
406 /* Do nothing if the string is empty, or if it is a space and there is
407 * no other text yet. */
408 if (!str
|| len
== 0 || strlen(str
) == 0
409 || (str
[0] == ' ' && str
[1] == 0 && state
->pslen
== 0))
417 /* Allocate more memory if necessary */
418 if (state
->nalloc_psel
- state
->pslen
< len
)
420 int incr
= STRSTORE_ALLOCSTEP
< len
? len
: STRSTORE_ALLOCSTEP
;
421 state
->nalloc_psel
+= incr
;
422 srenew(state
->pselstr
, state
->nalloc_psel
);
424 /* Append the token to the stored string */
425 strncpy(state
->pselstr
+ state
->pslen
, str
, len
);
427 state
->pselstr
[state
->pslen
] = 0;
431 _gmx_sel_init_lexer(yyscan_t
*scannerp
, struct gmx_ana_selcollection_t
*sc
,
432 bool bInteractive
, int maxnr
,
433 struct gmx_ana_indexgrps_t
*grps
)
435 gmx_sel_lexer_t
*state
;
438 rc
= _gmx_sel_yylex_init(scannerp
);
447 state
->nexpsel
= (maxnr
> 0 ? sc
->nr
+ maxnr
: -1);
449 state
->bInteractive
= bInteractive
;
450 state
->nalloc_input
= 0;
451 state
->inputstr
= NULL
;
453 snew(state
->pselstr
, STRSTORE_ALLOCSTEP
);
454 state
->pselstr
[0] = 0;
456 state
->nalloc_psel
= STRSTORE_ALLOCSTEP
;
458 snew(state
->mstack
, 20);
459 state
->mstack_alloc
= 20;
462 state
->nextparam
= NULL
;
463 state
->nextmethod
= NULL
;
464 state
->prev_pos_kw
= 0;
465 state
->bBoolNo
= FALSE
;
466 state
->bMatchOf
= FALSE
;
467 state
->bMatchBool
= FALSE
;
468 state
->bCmdStart
= TRUE
;
469 state
->bBuffer
= FALSE
;
471 _gmx_sel_yyset_extra(state
, *scannerp
);
476 _gmx_sel_free_lexer(yyscan_t scanner
)
478 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
480 sfree(state
->inputstr
);
481 sfree(state
->pselstr
);
482 sfree(state
->mstack
);
485 _gmx_sel_yy_delete_buffer(state
->buffer
, scanner
);
488 _gmx_sel_yylex_destroy(scanner
);
492 _gmx_sel_is_lexer_interactive(yyscan_t scanner
)
494 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
495 return state
->bInteractive
;
498 struct gmx_ana_selcollection_t
*
499 _gmx_sel_lexer_selcollection(yyscan_t scanner
)
501 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
505 struct gmx_ana_indexgrps_t
*
506 _gmx_sel_lexer_indexgrps(yyscan_t scanner
)
508 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
513 _gmx_sel_lexer_exp_selcount(yyscan_t scanner
)
515 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
516 return state
->nexpsel
;
520 _gmx_sel_lexer_pselstr(yyscan_t scanner
)
522 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
523 return state
->pselstr
;
527 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner
)
529 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
530 state
->pselstr
[0] = 0;
535 _gmx_sel_lexer_clear_method_stack(yyscan_t scanner
)
537 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
543 _gmx_sel_finish_method(yyscan_t scanner
)
545 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
554 _gmx_sel_set_lex_input_file(yyscan_t scanner
, FILE *fp
)
556 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
558 state
->bBuffer
= TRUE
;
559 state
->buffer
= _gmx_sel_yy_create_buffer(fp
, YY_BUF_SIZE
, scanner
);
560 _gmx_sel_yy_switch_to_buffer(state
->buffer
, scanner
);
564 _gmx_sel_set_lex_input_str(yyscan_t scanner
, const char *str
)
566 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
570 _gmx_sel_yy_delete_buffer(state
->buffer
, scanner
);
572 state
->bBuffer
= TRUE
;
573 state
->buffer
= _gmx_sel_yy_scan_string(str
, scanner
);