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 /* For some reason (at least on my Linux), fgets() doesn't return until
91 * the user presses Ctrl-D _twice_ at the end of a non-empty line.
92 * This can be a bit confusing for users, but there's not much we can
93 * do, and the chances of a normal user noticing this are not very big. */
94 while (fgets(ptr
, max_len
, stdin
))
96 int len
= strlen(ptr
);
99 if (len
>= 2 && ptr
[len
- 1] == '\n' && ptr
[len
- 2] == '\\')
101 if (state
->bInteractive
)
103 fprintf(stderr
, "... ");
106 else if (len
>= 1 && ptr
[len
- 1] == '\n')
110 else if (len
< max_len
- 1)
112 if (state
->bInteractive
)
114 fprintf(stderr
, "\n");
122 max_len
+= state
->nalloc_input
;
123 state
->nalloc_input
*= 2;
124 len
= ptr
- state
->inputstr
;
125 srenew(state
->inputstr
, state
->nalloc_input
);
126 ptr
= state
->inputstr
+ len
;
131 gmx_input("selection reading failed");
137 _gmx_sel_yyblex(YYSTYPE
*yylval
, yyscan_t yyscanner
)
139 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(yyscanner
);
143 if (!state
->bBuffer
&& !state
->inputstr
)
145 state
->nalloc_input
= 1024;
146 snew(state
->inputstr
, state
->nalloc_input
);
147 read_stdin_line(state
);
148 _gmx_sel_set_lex_input_str(yyscanner
, state
->inputstr
);
150 bCmdStart
= state
->bCmdStart
;
151 token
= _gmx_sel_yylex(yylval
, yyscanner
);
152 while (state
->inputstr
&& token
== 0 && read_stdin_line(state
))
154 _gmx_sel_set_lex_input_str(yyscanner
, state
->inputstr
);
155 token
= _gmx_sel_yylex(yylval
, yyscanner
);
157 if (token
== 0 && !bCmdStart
)
160 rtrim(state
->pselstr
);
162 state
->bCmdStart
= (token
== CMD_SEP
);
167 init_param_token(YYSTYPE
*yylval
, gmx_ana_selparam_t
*param
, gmx_bool bBoolNo
)
171 snew(yylval
->str
, strlen(param
->name
) + 3);
172 yylval
->str
[0] = 'n';
173 yylval
->str
[1] = 'o';
174 strcpy(yylval
->str
+2, param
->name
);
178 yylval
->str
= param
->name
? strdup(param
->name
) : NULL
;
184 init_method_token(YYSTYPE
*yylval
, gmx_ana_selmethod_t
*method
, gmx_bool bPosMod
,
185 gmx_sel_lexer_t
*state
)
187 /* If the previous token was not KEYWORD_POS, return EMPTY_POSMOD
188 * before the actual method to work around a limitation in Bison. */
189 if (!bPosMod
&& method
->type
!= POS_VALUE
)
191 state
->nextmethod
= method
;
194 yylval
->meth
= method
;
195 if (!(method
->flags
& SMETH_MODIFIER
) && method
->nparams
== 0)
198 switch (method
->type
)
200 case INT_VALUE
: return KEYWORD_NUMERIC
;
201 case REAL_VALUE
: return KEYWORD_NUMERIC
;
202 case STR_VALUE
: return KEYWORD_STR
;
203 case GROUP_VALUE
: return KEYWORD_GROUP
;
204 default: return INVALID
;
207 /* Method with parameters or a modifier */
208 if (method
->flags
& SMETH_MODIFIER
)
210 /* Remove all methods from the stack */
212 if (method
->param
[1].name
== NULL
)
214 state
->nextparam
= &method
->param
[1];
219 if (method
->param
[0].name
== NULL
)
221 state
->nextparam
= &method
->param
[0];
225 if (state
->msp
>= state
->mstack_alloc
)
227 state
->mstack_alloc
+= 10;
228 srenew(state
->mstack
, state
->mstack_alloc
);
230 state
->mstack
[state
->msp
] = method
;
231 if (method
->flags
& SMETH_MODIFIER
)
235 switch (method
->type
)
237 case INT_VALUE
: return METHOD_NUMERIC
;
238 case REAL_VALUE
: return METHOD_NUMERIC
;
239 case POS_VALUE
: return METHOD_POS
;
240 case GROUP_VALUE
: return METHOD_GROUP
;
246 return INVALID
; /* Should not be reached */
250 _gmx_sel_lexer_process_pending(YYSTYPE
*yylval
, gmx_sel_lexer_t
*state
)
252 if (state
->nextparam
)
254 gmx_ana_selparam_t
*param
= state
->nextparam
;
255 gmx_bool bBoolNo
= state
->bBoolNo
;
260 return END_OF_METHOD
;
262 state
->nextparam
= NULL
;
263 state
->bBoolNo
= FALSE
;
264 _gmx_sel_lexer_add_token(param
->name
, -1, state
);
265 return init_param_token(yylval
, param
, bBoolNo
);
267 if (state
->prev_pos_kw
> 0)
269 --state
->prev_pos_kw
;
271 if (state
->nextmethod
)
273 gmx_ana_selmethod_t
*method
= state
->nextmethod
;
275 state
->nextmethod
= NULL
;
276 return init_method_token(yylval
, method
, TRUE
, state
);
282 _gmx_sel_lexer_process_identifier(YYSTYPE
*yylval
, char *yytext
, size_t yyleng
,
283 gmx_sel_lexer_t
*state
)
285 gmx_sel_symrec_t
*symbol
;
288 /* Check if the identifier matches with a parameter name */
291 gmx_ana_selparam_t
*param
= NULL
;
292 gmx_bool bBoolNo
= FALSE
;
294 while (!param
&& sp
>= 0)
297 for (i
= 0; i
< state
->mstack
[sp
]->nparams
; ++i
)
299 /* Skip NULL parameters and too long parameters */
300 if (state
->mstack
[sp
]->param
[i
].name
== NULL
301 || strlen(state
->mstack
[sp
]->param
[i
].name
) > yyleng
)
305 if (!strncmp(state
->mstack
[sp
]->param
[i
].name
, yytext
, yyleng
))
307 param
= &state
->mstack
[sp
]->param
[i
];
310 /* Check separately for a 'no' prefix on gmx_boolean parameters */
311 if (state
->mstack
[sp
]->param
[i
].val
.type
== NO_VALUE
312 && yyleng
> 2 && yytext
[0] == 'n' && yytext
[1] == 'o'
313 && !strncmp(state
->mstack
[sp
]->param
[i
].name
, yytext
+2, yyleng
-2))
315 param
= &state
->mstack
[sp
]->param
[i
];
327 if (param
->val
.type
== NO_VALUE
&& !bBoolNo
)
329 state
->bMatchBool
= TRUE
;
333 state
->neom
= state
->msp
- sp
- 1;
334 state
->nextparam
= param
;
335 state
->bBoolNo
= bBoolNo
;
336 return END_OF_METHOD
;
338 _gmx_sel_lexer_add_token(param
->name
, -1, state
);
339 return init_param_token(yylval
, param
, bBoolNo
);
343 /* Check if the identifier matches with a symbol */
344 symbol
= _gmx_sel_find_symbol_len(state
->sc
->symtab
, yytext
, yyleng
, FALSE
);
345 /* If there is no match, return the token as a string */
348 yylval
->str
= gmx_strndup(yytext
, yyleng
);
349 _gmx_sel_lexer_add_token(yytext
, yyleng
, state
);
352 _gmx_sel_lexer_add_token(_gmx_sel_sym_name(symbol
), -1, state
);
353 symtype
= _gmx_sel_sym_type(symbol
);
354 /* Reserved symbols should have been caught earlier */
355 if (symtype
== SYMBOL_RESERVED
)
359 /* For variable symbols, return the type of the variable value */
360 if (symtype
== SYMBOL_VARIABLE
)
364 var
= _gmx_sel_sym_value_var(symbol
);
365 /* Return simple tokens for constant variables */
366 if (var
->type
== SEL_CONST
)
371 yylval
->i
= var
->v
.u
.i
[0];
374 yylval
->r
= var
->v
.u
.r
[0];
385 case INT_VALUE
: return VARIABLE_NUMERIC
;
386 case REAL_VALUE
: return VARIABLE_NUMERIC
;
387 case POS_VALUE
: return VARIABLE_POS
;
388 case GROUP_VALUE
: return VARIABLE_GROUP
;
389 default: return INVALID
;
393 /* For method symbols, return the correct type */
394 if (symtype
== SYMBOL_METHOD
)
396 gmx_ana_selmethod_t
*method
;
398 method
= _gmx_sel_sym_value_method(symbol
);
399 return init_method_token(yylval
, method
, state
->prev_pos_kw
> 0, state
);
401 /* For position symbols, we need to return KEYWORD_POS, but we also need
402 * some additional handling. */
403 if (symtype
== SYMBOL_POS
)
405 state
->bMatchOf
= TRUE
;
406 yylval
->str
= _gmx_sel_sym_name(symbol
);
407 state
->prev_pos_kw
= 2;
410 /* Should not be reached */
415 _gmx_sel_lexer_add_token(const char *str
, int len
, gmx_sel_lexer_t
*state
)
417 /* Do nothing if the string is empty, or if it is a space and there is
418 * no other text yet, or if there already is a space. */
419 if (!str
|| len
== 0 || strlen(str
) == 0
420 || (str
[0] == ' ' && str
[1] == 0
421 && (state
->pslen
== 0 || state
->pselstr
[state
->pslen
- 1] == ' ')))
429 /* Allocate more memory if necessary */
430 if (state
->nalloc_psel
- state
->pslen
< len
)
432 int incr
= STRSTORE_ALLOCSTEP
< len
? len
: STRSTORE_ALLOCSTEP
;
433 state
->nalloc_psel
+= incr
;
434 srenew(state
->pselstr
, state
->nalloc_psel
);
436 /* Append the token to the stored string */
437 strncpy(state
->pselstr
+ state
->pslen
, str
, len
);
439 state
->pselstr
[state
->pslen
] = 0;
443 _gmx_sel_init_lexer(yyscan_t
*scannerp
, struct gmx_ana_selcollection_t
*sc
,
444 gmx_bool bInteractive
, int maxnr
,
445 struct gmx_ana_indexgrps_t
*grps
)
447 gmx_sel_lexer_t
*state
;
450 rc
= _gmx_sel_yylex_init(scannerp
);
459 state
->nexpsel
= (maxnr
> 0 ? sc
->nr
+ maxnr
: -1);
461 state
->bInteractive
= bInteractive
;
462 state
->nalloc_input
= 0;
463 state
->inputstr
= NULL
;
465 snew(state
->pselstr
, STRSTORE_ALLOCSTEP
);
466 state
->pselstr
[0] = 0;
468 state
->nalloc_psel
= STRSTORE_ALLOCSTEP
;
470 snew(state
->mstack
, 20);
471 state
->mstack_alloc
= 20;
474 state
->nextparam
= NULL
;
475 state
->nextmethod
= NULL
;
476 state
->prev_pos_kw
= 0;
477 state
->bBoolNo
= FALSE
;
478 state
->bMatchOf
= FALSE
;
479 state
->bMatchBool
= FALSE
;
480 state
->bCmdStart
= TRUE
;
481 state
->bBuffer
= FALSE
;
483 _gmx_sel_yyset_extra(state
, *scannerp
);
488 _gmx_sel_free_lexer(yyscan_t scanner
)
490 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
492 sfree(state
->inputstr
);
493 sfree(state
->pselstr
);
494 sfree(state
->mstack
);
497 _gmx_sel_yy_delete_buffer(state
->buffer
, scanner
);
500 _gmx_sel_yylex_destroy(scanner
);
504 _gmx_sel_is_lexer_interactive(yyscan_t scanner
)
506 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
507 return state
->bInteractive
;
510 struct gmx_ana_selcollection_t
*
511 _gmx_sel_lexer_selcollection(yyscan_t scanner
)
513 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
517 struct gmx_ana_indexgrps_t
*
518 _gmx_sel_lexer_indexgrps(yyscan_t scanner
)
520 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
525 _gmx_sel_lexer_exp_selcount(yyscan_t scanner
)
527 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
528 return state
->nexpsel
;
532 _gmx_sel_lexer_pselstr(yyscan_t scanner
)
534 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
535 return state
->pselstr
;
539 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner
)
541 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
542 state
->pselstr
[0] = 0;
547 _gmx_sel_lexer_clear_method_stack(yyscan_t scanner
)
549 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
555 _gmx_sel_finish_method(yyscan_t scanner
)
557 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
566 _gmx_sel_set_lex_input_file(yyscan_t scanner
, FILE *fp
)
568 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
570 state
->bBuffer
= TRUE
;
571 state
->buffer
= _gmx_sel_yy_create_buffer(fp
, YY_BUF_SIZE
, scanner
);
572 _gmx_sel_yy_switch_to_buffer(state
->buffer
, scanner
);
576 _gmx_sel_set_lex_input_str(yyscan_t scanner
, const char *str
)
578 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
582 _gmx_sel_yy_delete_buffer(state
->buffer
, scanner
);
584 state
->bBuffer
= TRUE
;
585 state
->buffer
= _gmx_sel_yy_scan_string(str
, scanner
);