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
54 #include <selmethod.h>
56 #include "parsetree.h"
57 #include "selcollection.h"
63 #include "scanner_internal.h"
65 #define STRSTORE_ALLOCSTEP 1000
67 /* These are defined as macros in the generated scanner_flex.h.
68 * We undefine them here to have them as variable names in the subroutines.
69 * There are other ways of doing this, but this is probably the easiest. */
75 read_stdin_line(gmx_sel_lexer_t
*state
)
77 char *ptr
= state
->inputstr
;
78 int max_len
= state
->nalloc_input
;
85 if (state
->bInteractive
)
87 fprintf(stderr
, "> ");
89 while (fgets(ptr
, max_len
, stdin
))
91 int len
= strlen(ptr
);
94 if (len
>= 2 && ptr
[len
- 1] == '\n' && ptr
[len
- 2] == '\\')
96 if (state
->bInteractive
)
98 fprintf(stderr
, "... ");
101 else if (len
>= 1 && ptr
[len
- 1] == '\n')
105 else if (len
< max_len
- 1)
107 if (state
->bInteractive
)
109 fprintf(stderr
, "\n");
117 max_len
+= state
->nalloc_input
;
118 state
->nalloc_input
*= 2;
119 len
= ptr
- state
->inputstr
;
120 srenew(state
->inputstr
, state
->nalloc_input
);
121 ptr
= state
->inputstr
+ len
;
126 gmx_input("selection reading failed");
128 state
->bCmdStart
= totlen
> 0;
133 _gmx_sel_yyblex(YYSTYPE
*yylval
, yyscan_t yyscanner
)
135 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(yyscanner
);
138 if (!state
->bBuffer
&& !state
->inputstr
)
140 state
->nalloc_input
= 1024;
141 snew(state
->inputstr
, state
->nalloc_input
);
142 read_stdin_line(state
);
143 _gmx_sel_set_lex_input_str(yyscanner
, state
->inputstr
);
145 token
= _gmx_sel_yylex(yylval
, yyscanner
);
146 while (state
->inputstr
&& token
== 0 && read_stdin_line(state
))
148 _gmx_sel_set_lex_input_str(yyscanner
, state
->inputstr
);
149 token
= _gmx_sel_yylex(yylval
, yyscanner
);
155 init_param_token(YYSTYPE
*yylval
, gmx_ana_selparam_t
*param
, bool bBoolNo
)
159 snew(yylval
->str
, strlen(param
->name
) + 3);
160 yylval
->str
[0] = 'n';
161 yylval
->str
[1] = 'o';
162 strcpy(yylval
->str
+2, param
->name
);
166 yylval
->str
= param
->name
? strdup(param
->name
) : NULL
;
172 init_method_token(YYSTYPE
*yylval
, gmx_ana_selmethod_t
*method
, bool bPosMod
,
173 gmx_sel_lexer_t
*state
)
175 /* If the previous token was not KEYWORD_POS, return EMPTY_POSMOD
176 * before the actual method to work around a limitation in Bison. */
177 if (!bPosMod
&& method
->type
!= POS_VALUE
)
179 state
->nextmethod
= method
;
182 yylval
->meth
= method
;
183 if (!(method
->flags
& SMETH_MODIFIER
) && method
->nparams
== 0)
186 switch (method
->type
)
188 case INT_VALUE
: return KEYWORD_NUMERIC
;
189 case REAL_VALUE
: return KEYWORD_NUMERIC
;
190 case STR_VALUE
: return KEYWORD_STR
;
191 case GROUP_VALUE
: return KEYWORD_GROUP
;
192 default: return INVALID
;
195 /* Method with parameters or a modifier */
196 if (method
->flags
& SMETH_MODIFIER
)
198 /* Remove all methods from the stack */
200 if (method
->param
[1].name
== NULL
)
202 state
->nextparam
= &method
->param
[1];
207 if (method
->param
[0].name
== NULL
)
209 state
->nextparam
= &method
->param
[0];
213 if (state
->msp
>= state
->mstack_alloc
)
215 state
->mstack_alloc
+= 10;
216 srenew(state
->mstack
, state
->mstack_alloc
);
218 state
->mstack
[state
->msp
] = method
;
219 if (method
->flags
& SMETH_MODIFIER
)
223 switch (method
->type
)
225 case INT_VALUE
: return METHOD_NUMERIC
;
226 case REAL_VALUE
: return METHOD_NUMERIC
;
227 case POS_VALUE
: return METHOD_POS
;
228 case GROUP_VALUE
: return METHOD_GROUP
;
234 return INVALID
; /* Should not be reached */
238 _gmx_sel_lexer_process_pending(YYSTYPE
*yylval
, gmx_sel_lexer_t
*state
)
240 if (state
->nextparam
)
242 gmx_ana_selparam_t
*param
= state
->nextparam
;
243 bool bBoolNo
= state
->bBoolNo
;
248 return END_OF_METHOD
;
250 state
->nextparam
= NULL
;
251 state
->bBoolNo
= FALSE
;
252 _gmx_sel_lexer_add_token(param
->name
, -1, state
);
253 return init_param_token(yylval
, param
, bBoolNo
);
255 if (state
->prev_pos_kw
> 0)
257 --state
->prev_pos_kw
;
259 if (state
->nextmethod
)
261 gmx_ana_selmethod_t
*method
= state
->nextmethod
;
263 state
->nextmethod
= NULL
;
264 return init_method_token(yylval
, method
, TRUE
, state
);
270 _gmx_sel_lexer_process_identifier(YYSTYPE
*yylval
, char *yytext
, size_t yyleng
,
271 gmx_sel_lexer_t
*state
)
273 gmx_sel_symrec_t
*symbol
;
276 /* Check if the identifier matches with a parameter name */
279 gmx_ana_selparam_t
*param
= NULL
;
280 bool bBoolNo
= FALSE
;
282 while (!param
&& sp
>= 0)
285 for (i
= 0; i
< state
->mstack
[sp
]->nparams
; ++i
)
287 /* Skip NULL parameters and too long parameters */
288 if (state
->mstack
[sp
]->param
[i
].name
== NULL
289 || strlen(state
->mstack
[sp
]->param
[i
].name
) > yyleng
)
293 if (!strncmp(state
->mstack
[sp
]->param
[i
].name
, yytext
, yyleng
))
295 param
= &state
->mstack
[sp
]->param
[i
];
298 /* Check separately for a 'no' prefix on boolean parameters */
299 if (state
->mstack
[sp
]->param
[i
].val
.type
== NO_VALUE
300 && yyleng
> 2 && yytext
[0] == 'n' && yytext
[1] == 'o'
301 && !strncmp(state
->mstack
[sp
]->param
[i
].name
, yytext
+2, yyleng
-2))
303 param
= &state
->mstack
[sp
]->param
[i
];
315 if (param
->val
.type
== NO_VALUE
&& !bBoolNo
)
317 state
->bMatchBool
= TRUE
;
321 state
->neom
= state
->msp
- sp
- 1;
322 state
->nextparam
= param
;
323 state
->bBoolNo
= bBoolNo
;
324 return END_OF_METHOD
;
326 _gmx_sel_lexer_add_token(param
->name
, -1, state
);
327 return init_param_token(yylval
, param
, bBoolNo
);
331 /* Check if the identifier matches with a symbol */
332 symbol
= _gmx_sel_find_symbol_len(state
->sc
->symtab
, yytext
, yyleng
, FALSE
);
333 /* If there is no match, return the token as a string */
336 yylval
->str
= strndup(yytext
, yyleng
);
337 _gmx_sel_lexer_add_token(yytext
, yyleng
, state
);
340 _gmx_sel_lexer_add_token(_gmx_sel_sym_name(symbol
), -1, state
);
341 symtype
= _gmx_sel_sym_type(symbol
);
342 /* Reserved symbols should have been caught earlier */
343 if (symtype
== SYMBOL_RESERVED
)
347 /* For variable symbols, return the type of the variable value */
348 if (symtype
== SYMBOL_VARIABLE
)
352 var
= _gmx_sel_sym_value_var(symbol
);
353 /* Return simple tokens for constant variables */
354 if (var
->type
== SEL_CONST
)
359 yylval
->i
= var
->v
.u
.i
[0];
362 yylval
->r
= var
->v
.u
.r
[0];
373 case INT_VALUE
: return VARIABLE_NUMERIC
;
374 case REAL_VALUE
: return VARIABLE_NUMERIC
;
375 case POS_VALUE
: return VARIABLE_POS
;
376 case GROUP_VALUE
: return VARIABLE_GROUP
;
377 default: return INVALID
;
381 /* For method symbols, return the correct type */
382 if (symtype
== SYMBOL_METHOD
)
384 gmx_ana_selmethod_t
*method
;
386 method
= _gmx_sel_sym_value_method(symbol
);
387 return init_method_token(yylval
, method
, state
->prev_pos_kw
> 0, state
);
389 /* For position symbols, we need to return KEYWORD_POS, but we also need
390 * some additional handling. */
391 if (symtype
== SYMBOL_POS
)
393 state
->bMatchOf
= TRUE
;
394 yylval
->str
= _gmx_sel_sym_name(symbol
);
395 state
->prev_pos_kw
= 2;
398 /* Should not be reached */
403 _gmx_sel_lexer_add_token(const char *str
, int len
, gmx_sel_lexer_t
*state
)
405 /* Do nothing if the string is empty, or if it is a space and there is
406 * no other text yet. */
407 if (!str
|| len
== 0 || strlen(str
) == 0
408 || (str
[0] == ' ' && str
[1] == 0 && state
->pslen
== 0))
416 /* Allocate more memory if necessary */
417 if (state
->nalloc_psel
- state
->pslen
< len
)
419 int incr
= STRSTORE_ALLOCSTEP
< len
? len
: STRSTORE_ALLOCSTEP
;
420 state
->nalloc_psel
+= incr
;
421 srenew(state
->pselstr
, state
->nalloc_psel
);
423 /* Append the token to the stored string */
424 strncpy(state
->pselstr
+ state
->pslen
, str
, len
);
426 state
->pselstr
[state
->pslen
] = 0;
430 _gmx_sel_init_lexer(yyscan_t
*scannerp
, struct gmx_ana_selcollection_t
*sc
,
431 bool bInteractive
, int maxnr
,
432 struct gmx_ana_indexgrps_t
*grps
)
434 gmx_sel_lexer_t
*state
;
437 rc
= _gmx_sel_yylex_init(scannerp
);
446 state
->nexpsel
= (maxnr
> 0 ? sc
->nr
+ maxnr
: -1);
448 state
->bInteractive
= bInteractive
;
449 state
->nalloc_input
= 0;
450 state
->inputstr
= NULL
;
452 snew(state
->pselstr
, STRSTORE_ALLOCSTEP
);
453 state
->pselstr
[0] = 0;
455 state
->nalloc_psel
= STRSTORE_ALLOCSTEP
;
457 snew(state
->mstack
, 20);
458 state
->mstack_alloc
= 20;
461 state
->nextparam
= NULL
;
462 state
->nextmethod
= NULL
;
463 state
->prev_pos_kw
= 0;
464 state
->bBoolNo
= FALSE
;
465 state
->bMatchOf
= FALSE
;
466 state
->bMatchBool
= FALSE
;
467 state
->bCmdStart
= TRUE
;
468 state
->bBuffer
= FALSE
;
470 _gmx_sel_yyset_extra(state
, *scannerp
);
475 _gmx_sel_free_lexer(yyscan_t scanner
)
477 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
479 sfree(state
->inputstr
);
480 sfree(state
->pselstr
);
481 sfree(state
->mstack
);
484 _gmx_sel_yy_delete_buffer(state
->buffer
, scanner
);
487 _gmx_sel_yylex_destroy(scanner
);
491 _gmx_sel_is_lexer_interactive(yyscan_t scanner
)
493 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
494 return state
->bInteractive
;
497 struct gmx_ana_selcollection_t
*
498 _gmx_sel_lexer_selcollection(yyscan_t scanner
)
500 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
504 struct gmx_ana_indexgrps_t
*
505 _gmx_sel_lexer_indexgrps(yyscan_t scanner
)
507 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
512 _gmx_sel_lexer_exp_selcount(yyscan_t scanner
)
514 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
515 return state
->nexpsel
;
519 _gmx_sel_lexer_pselstr(yyscan_t scanner
)
521 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
522 return state
->pselstr
;
526 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner
)
528 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
529 state
->pselstr
[0] = 0;
534 _gmx_sel_lexer_clear_method_stack(yyscan_t scanner
)
536 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
542 _gmx_sel_finish_method(yyscan_t scanner
)
544 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
553 _gmx_sel_set_lex_input_file(yyscan_t scanner
, FILE *fp
)
555 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
557 state
->bBuffer
= TRUE
;
558 state
->buffer
= _gmx_sel_yy_create_buffer(fp
, YY_BUF_SIZE
, scanner
);
559 _gmx_sel_yy_switch_to_buffer(state
->buffer
, scanner
);
563 _gmx_sel_set_lex_input_str(yyscan_t scanner
, const char *str
)
565 gmx_sel_lexer_t
*state
= _gmx_sel_yyget_extra(scanner
);
569 _gmx_sel_yy_delete_buffer(state
->buffer
, scanner
);
571 state
->bBuffer
= TRUE
;
572 state
->buffer
= _gmx_sel_yy_scan_string(str
, scanner
);