1
/*============================================================================
2
* Expression handling for entity selection based on groups or attributes
3
*============================================================================*/
5
/*----------------------------------------------------------------------------*/
8
This file is part of Code_Saturne, a general-purpose CFD tool.
10
Copyright (C) 1998-2011 EDF S.A.
12
This program is free software; you can redistribute it and/or modify it under
13
the terms of the GNU General Public License as published by the Free Software
14
Foundation; either version 2 of the License, or (at your option) any later
17
This program is distributed in the hope that it will be useful, but WITHOUT
18
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
22
You should have received a copy of the GNU General Public License along with
23
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
24
Street, Fifth Floor, Boston, MA 02110-1301, USA.
27
/*----------------------------------------------------------------------------*/
29
#if defined(HAVE_CONFIG_H)
30
#include "cs_config.h"
33
/*----------------------------------------------------------------------------
34
* Standard C library headers
35
*----------------------------------------------------------------------------*/
43
/*----------------------------------------------------------------------------
45
*----------------------------------------------------------------------------*/
48
#include <bft_error.h>
49
#include <bft_printf.h>
51
/*----------------------------------------------------------------------------
53
*----------------------------------------------------------------------------*/
56
#include "fvm_config_defs.h"
58
/*----------------------------------------------------------------------------
59
* Header for the current file
60
*----------------------------------------------------------------------------*/
62
#include "fvm_selector_postfix.h"
64
/*----------------------------------------------------------------------------*/
69
} /* Fake brace to force Emacs auto-indentation back to column 0 */
71
#endif /* __cplusplus */
73
/*=============================================================================
75
*============================================================================*/
78
* Allowed operand types (bit mask)
81
#define _OPERAND_INT (1 << 0)
82
#define _OPERAND_DOUBLE (1 << 1)
83
#define _OPERAND_STRING (1 << 2)
84
#define _OPERAND_GEOMETRIC (1 << 3)
86
/* Base stack length */
88
#define BASE_STACK_SIZE 32
90
/* Geometric operation macros*/
92
#define _DOT_PRODUCT(v1, v2) \
93
(v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2])
96
sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])
98
/*============================================================================
99
* Local type definitions
100
*============================================================================*/
102
/*----------------------------------------------------------------------------
103
* Types of arguments or oprands for an operator
104
*----------------------------------------------------------------------------*/
108
OT_L_PAREN, /* Left parenthesis */
109
OT_R_PAREN, /* Right parenthesis */
110
OT_UNARY, /* Unary function (arg to the right) */
111
OT_BINARY, /* Binary function (args left and right) */
112
OT_FUNCTION, /* Built-in functions (args between brackets) */
113
OT_COORD_CONDITION, /* Condition on coordinates (<, <=, >, >=) */
114
OT_DEFINITION, /* Sub-expression definition (not implemented) */
115
OT_MATH_FUNCTION, /* Mathematical function (not implemented) */
116
OT_NONE /* Not an operaror */
120
/*----------------------------------------------------------------------------
121
* List of operator codes and names
122
*----------------------------------------------------------------------------*/
153
static const char *_operator_name[] = {"(", ")",
154
"not", "and", "or", "xor",
155
"all", "no_group", "range",
156
"normal", "plane", "box",
157
"cylinder", "sphere",
158
">", "<", ">=", "<=",
161
/*----------------------------------------------------------------------------
162
* Types of postfix elements
163
*----------------------------------------------------------------------------*/
175
/*----------------------------------------------------------------------------
176
* Definition of a tokenized expression
177
*----------------------------------------------------------------------------*/
181
int n_tokens; /* Number of tokens in expression */
182
int *infix_id; /* Starting id in infix for each token */
183
int *token_id; /* Starting id for each token */
184
_Bool *protected; /* Indicates if a token was protected
185
by quotes or a backslash character
186
(and thus cannot be a keyword) */
188
int size; /* Current string size */
189
int max_size; /* Maximum string size */
191
char *tokens; /* Tokens array */
195
/*----------------------------------------------------------------------------
196
* Operator definition
197
*----------------------------------------------------------------------------*/
201
_operator_code_t code; /* Operator code number */
202
_operator_type_t type; /* Operator type */
204
int priority; /* Priority */
206
char name[16]; /* Operator name string */
210
/*----------------------------------------------------------------------------
212
*----------------------------------------------------------------------------*/
216
int n_operators; /* Number of possible operators */
217
_operator_t *operators; /* Array of allowed operators */
219
int n_keywords; /* Total number of keywords */
220
int *keyword_op_id; /* Operator id for each keyword */
221
char **keyword; /* Pointer to individual keywords */
223
size_t keywords_size; /* Size of keyword buffer */
224
char *keywords; /* Pointer to keyword buffer */
228
/*----------------------------------------------------------------------------
229
* Stack of parsed operator elements
230
*----------------------------------------------------------------------------*/
234
const _operator_t *op; /* Pointer to operator definition */
235
int token_id; /* Associated token's id */
241
size_t size; /* Current memory size */
242
size_t max_size; /* Maximum memory size */
244
_stack_entry_t _elements[BASE_STACK_SIZE]; /* Base working stack */
245
_stack_entry_t *elements; /* Pointer to _elements
250
/*============================================================================
252
*============================================================================*/
254
/*----------------------------------------------------------------------------
255
* Postfix expression object
256
*----------------------------------------------------------------------------*/
258
struct _fvm_selector_postfix_t {
260
_Bool coords_dependency; /* Does evaluation require coordinates ? */
261
_Bool normals_dependency; /* Does evaluation require normals ? */
263
size_t size; /* Current memory size */
264
size_t max_size; /* Maximum memory size */
266
char *infix; /* Copy of original infix expression */
267
unsigned char *elements; /* Contents array */
269
int n_missing_operands; /* Number of operands corresponding to
270
missing group names */
271
char **missing_operand; /* Array of missing group names */
275
/*============================================================================
277
*============================================================================*/
279
/* Reference count and pointer to global parser object */
281
static int _n_parser_references = 0;
282
static _parser_t *_parser = NULL;
284
/* Compute sizes so as to have aligned data */
286
static const size_t _postfix_type_size
287
= sizeof(size_t)*( (sizeof(_postfix_type_t)/sizeof(size_t))
288
+ (sizeof(_postfix_type_t)%sizeof(size_t) ? 1 : 0));
289
static const size_t _postfix_opcode_size
290
= sizeof(size_t)*( (sizeof(_operator_code_t)/sizeof(size_t))
291
+ (sizeof(_operator_code_t)%sizeof(size_t) ? 1 : 0));
292
static const size_t _postfix_int_size
293
= sizeof(size_t)*( (sizeof(int)/sizeof(size_t))
294
+ (sizeof(int)%sizeof(size_t) ? 1 : 0));
295
static const size_t _postfix_float_size
296
= sizeof(size_t)*( (sizeof(double)/sizeof(size_t))
297
+ (sizeof(double)%sizeof(size_t) ? 1 : 0));
299
/*============================================================================
300
* Private function definitions
301
*============================================================================*/
303
/*----------------------------------------------------------------------------
304
* Add an operator definition to a parser.
307
* this_parser <-> Parser to which operator should be added
308
* name <-- Operator name (truncated at 15 characters)
309
* operator_code <-- Unique operator code
310
* operator_type <-- Operator type (unary, binary, function)
311
* priority <-- Operator priority
312
* n_keywords <-- Number of associated keywords
313
* keywords <-- Array of associated keywords
314
*----------------------------------------------------------------------------*/
317
_add_operator(_parser_t *this_parser,
319
_operator_code_t operator_code,
320
_operator_type_t operator_type,
323
const char **keywords)
329
assert(this_parser != NULL);
330
assert(n_keywords > 0);
332
/* Resize structures */
334
BFT_REALLOC(this_parser->operators,
335
this_parser->n_operators + 1,
338
if (n_keywords > 0) {
340
size_t keywords_size = 0;
342
for (i = 0; i < n_keywords; i++)
343
keywords_size += (strlen(keywords[i]) + 1);
345
BFT_REALLOC(this_parser->keyword_op_id,
346
this_parser->n_keywords + n_keywords,
349
BFT_REALLOC(this_parser->keyword,
350
this_parser->n_keywords + n_keywords,
353
BFT_REALLOC(this_parser->keywords,
354
this_parser->keywords_size + keywords_size,
359
/* Fill structures */
361
i = this_parser->n_operators;
363
this_parser->operators[i].code = operator_code;
364
this_parser->operators[i].priority = priority;
365
this_parser->operators[i].type = operator_type;
367
strncpy(this_parser->operators[i].name, name, 15);
368
this_parser->operators[i].name[15] = '\0';
370
for (i = 0; i < n_keywords; i++) {
372
size_t l = strlen(keywords[i]) + 1;
374
this_parser->keyword_op_id[this_parser->n_keywords]
375
= this_parser->n_operators;
377
memcpy(this_parser->keywords + this_parser->keywords_size,
381
this_parser->n_keywords += 1;
382
this_parser->keywords_size += l;
386
this_parser->n_operators += 1;
389
/*----------------------------------------------------------------------------
390
* Creation of a parser object.
395
* pointer to new parser
396
*----------------------------------------------------------------------------*/
403
const char *kw_l_paren[] = {"("};
404
const char *kw_r_paren[] = {")"};
406
const char *kw_not[] = {"not", "!", "!=", "NOT"};
407
const char *kw_and[] = {"and", "&", "&&", "AND"};
408
const char *kw_or[] = {"or", "|", "||", ",", ";", "OR"};
409
const char *kw_xor[] = {"xor", "^", "XOR"};
410
const char *kw_all[] = {"all", "ALL"};
411
const char *kw_ngr[] = {"no_group", "NO_GROUP"};
412
const char *kw_rng[] = {"range", "RANGE"};
414
const char *kw_nrm[] = {"normal", "NORMAL"};
415
const char *kw_pln[] = {"plane", "PLANE"};
416
const char *kw_box[] = {"box", "BOX"};
417
const char *kw_cyl[] = {"cylinder", "CYLINDER"};
418
const char *kw_sph[] = {"sphere", "SPHERE"};
420
const char *kw_gt[] = {">"};
421
const char *kw_lt[] = {"<"};
422
const char *kw_ge[] = {">="};
423
const char *kw_le[] = {"<="};
427
/* Create base structure */
429
BFT_MALLOC(p, 1, _parser_t);
435
p->keyword_op_id = NULL;
438
p->keywords_size = 0;
441
/* Add operator definitions */
443
_add_operator(p, "(", OC_L_PAREN, OT_L_PAREN, 0, 1, kw_l_paren);
444
_add_operator(p, ")", OC_R_PAREN, OT_R_PAREN, 0, 1, kw_r_paren);
446
_add_operator(p, "not", OC_NOT, OT_UNARY, 3, 4, kw_not);
447
_add_operator(p, "and", OC_AND, OT_BINARY, 2, 4, kw_and);
448
_add_operator(p, "or", OC_OR, OT_BINARY, 1, 6, kw_or);
449
_add_operator(p, "xor", OC_XOR, OT_BINARY, 1, 3, kw_xor);
451
_add_operator(p, "all", OC_ALL, OT_FUNCTION, 4, 2, kw_all);
452
_add_operator(p, "no_group", OC_NO_GROUP, OT_FUNCTION, 4, 2, kw_ngr);
453
_add_operator(p, "range", OC_RANGE, OT_FUNCTION, 4, 2, kw_rng);
455
_add_operator(p, "normal", OC_NORMAL, OT_FUNCTION, 4, 2, kw_nrm);
456
_add_operator(p, "plane", OC_PLANE, OT_FUNCTION, 4, 2, kw_pln);
457
_add_operator(p, "box", OC_BOX, OT_FUNCTION, 4, 2, kw_box);
458
_add_operator(p, "cylinder", OC_CYLINDER, OT_FUNCTION, 4, 2, kw_cyl);
459
_add_operator(p, "sphere", OC_SPHERE, OT_FUNCTION, 4, 2, kw_sph);
461
_add_operator(p, ">", OC_GT, OT_COORD_CONDITION, 4, 1, kw_gt);
462
_add_operator(p, "<", OC_LT, OT_COORD_CONDITION, 4, 1, kw_lt);
463
_add_operator(p, ">=", OC_GE, OT_COORD_CONDITION, 4, 1, kw_ge);
464
_add_operator(p, "<=", OC_LE, OT_COORD_CONDITION, 4, 1, kw_le);
466
/* Build keyword pointers */
468
p->keyword[0] = p->keywords;
470
for (i = 1; i < p->n_keywords; i++)
472
= p->keyword[i-1] + strlen(p->keyword[i-1]) + 1;
474
/* Return parser object */
479
/*----------------------------------------------------------------------------
480
* Destruction of a parser.
483
* this_parser <-> parser to destroy
484
*----------------------------------------------------------------------------*/
487
_parser_destroy(_parser_t **this_parser)
489
if (*this_parser != NULL) {
491
BFT_FREE((*this_parser)->operators);
492
BFT_FREE((*this_parser)->keyword_op_id);
493
BFT_FREE((*this_parser)->keyword);
494
BFT_FREE((*this_parser)->keywords);
496
BFT_FREE(*this_parser);
501
/*----------------------------------------------------------------------------
502
* Print content of a parser object.
505
* this_parser <-- parser object
506
*----------------------------------------------------------------------------*/
509
_parser_dump(const _parser_t *this_parser)
513
const char *type_name[] = {"(", ")", "unary", "binary", "function",
514
"coord condition", "definition", "math_func"};
516
if (this_parser == NULL)
519
/* Global indicators */
520
/*-------------------*/
524
"Number of operators: %d\n"
525
"Number of keywords: %d\n\n",
526
this_parser->n_operators,
527
this_parser->n_keywords);
530
/* Operators and related part of keywords array */
532
if (this_parser->n_operators > 0)
533
bft_printf("Operators:\n"
534
" id | name | code | pri | type \n"
535
" ------------------------------------\n");
537
for (i = 0; i < this_parser->n_operators; i++) {
538
const _operator_t *op = this_parser->operators + i;
539
bft_printf(" %4d | %8s | %4d | %3d | %s\n",
540
i, op->name, op->code, op->priority, type_name[op->type]);
543
if (this_parser->n_keywords > 0)
546
" id | op_id | name\n"
547
" ------------------\n");
549
for (i = 0; i < this_parser->n_keywords; i++)
550
bft_printf(" %4d | %5d | %s\n",
551
i, this_parser->keyword_op_id[i], this_parser->keyword[i]);
556
/*----------------------------------------------------------------------------
557
* Tokenize an infix expression string.
560
* infix <-- string parsed
563
* a tokenized_t structure corresponding to the infix string
564
*----------------------------------------------------------------------------*/
567
_tokenize(const char *infix)
569
int i, l, tok_len, start_quote_id;
570
int protected; /* 0 for unprotected, 1 for protected char, 2 for substring,
571
3 for protected char in substring */
589
/* Allocate tokenization structure */
593
te.max_size = l*2 + 1; /* Allows for insertion of NULL chars after
594
each character (worst case), so no size
595
increase will be necessary */
597
BFT_MALLOC(te.infix_id, l, int);
598
BFT_MALLOC(te.token_id, l, int);
599
BFT_MALLOC(te.protected, l, _Bool);
600
BFT_MALLOC(te.tokens, te.max_size, char);
602
for (i = 0; i < l; i++)
603
te.protected[i] = false;
605
i = 0; /* String position marker */
606
start_quote_id = l; /* Start position marker for quoted strings
607
(unset if j == j, set if j < l) */
616
/* Regular case, where previous character was not protected */
618
if (protected == 0) {
620
/* Protection character */
624
te.protected[te.n_tokens] = true;
627
/* Fully protected string */
629
else if (c == '"' || c == '\'') {
632
te.protected[te.n_tokens] = true;
637
else if (c == ' ' || c == '\t' || c == '\n'|| c == '\r') {
638
if (tok_len > 0) { /* Finish previous token */
639
te.token_id[te.n_tokens] = te.size;
640
te.tokens[te.size + tok_len] = '\0';
642
te.size += tok_len+1;
647
/* Other punctuation characters */
649
else if ( c == '(' || c == ')'
650
|| c == '[' || c == ']'
651
|| c == ',' || c == ';'
652
|| c == '!' || c == '^' || c == '|' || c == '&'
653
|| c == '=' || c == '<' || c == '>') {
657
if (tok_len > 0) { /* Finish previous token */
658
te.token_id[te.n_tokens] = te.size;
659
te.tokens[te.size + tok_len] = '\0';
661
te.size += tok_len+1;
665
/* Add token, handling possible 2-character punctuation */
667
te.token_id[te.n_tokens] = te.size;
668
te.tokens[te.size] = c;
673
if ( ((c == '=' || c == '<' || c == '>') && c2 == '=')
674
|| (c == '!' && c2 == '=')
675
|| (c == '|' && c2 == '|')
676
|| (c == '&' && c2 == '&')) {
678
te.tokens[te.size + 1] = '=';
679
te.tokens[te.size + 2] = '\0';
683
te.tokens[te.size + 1] = '\0';
686
te.infix_id[te.n_tokens] = i;
691
/* Regular characters (token) */
694
te.tokens[te.size + tok_len] = infix[i];
696
te.infix_id[te.n_tokens] = i;
702
/* Cases where previous character was protected */
704
else if (protected == 1) {
707
te.tokens[te.size + tok_len] = infix[i];
709
te.infix_id[te.n_tokens] = i;
714
else if (protected == 2) {
716
/* Single protection character */
721
/* End of string protection */
723
else if (c == infix[start_quote_id]) {
729
te.tokens[te.size + tok_len] = infix[i];
731
te.infix_id[te.n_tokens] = i;
737
else { /* if (protected == 3) */
739
te.tokens[te.size + tok_len] = infix[i];
741
te.infix_id[te.n_tokens] = i;
749
} /* End of loop in infix string characters */
751
if (tok_len > 0) { /* Finish previous token */
752
te.token_id[te.n_tokens] = te.size;
753
te.tokens[te.size + tok_len] = '\0';
755
te.size += tok_len+1;
760
bft_error(__FILE__, __LINE__, 0,
761
_("Error tokenizing expression:\n"
763
"Missing character after \\\n"),
765
else if (protected >= 2)
766
bft_error(__FILE__, __LINE__, 0,
767
_("Error tokenizing expression:\n"
769
"Missing closing quote for subexpression:\n"
771
infix, infix + start_quote_id);
773
/* Resize to adjusted size */
775
BFT_REALLOC(te.infix_id, te.n_tokens, int);
776
BFT_REALLOC(te.token_id, te.n_tokens, int);
777
BFT_REALLOC(te.protected, te.n_tokens, _Bool);
778
BFT_REALLOC(te.tokens, te.size, char);
780
/* Return tokenization structure */
785
/*----------------------------------------------------------------------------
786
* Empty a tokenized expression string.
789
* te <-> tokenized expression
790
*----------------------------------------------------------------------------*/
793
_empty_tokenized(_tokenized_t *te)
798
BFT_FREE(te->infix_id);
799
BFT_FREE(te->token_id);
800
BFT_FREE(te->protected);
801
BFT_FREE(te->tokens);
804
/*----------------------------------------------------------------------------
805
* Dump a tokenized expression string.
808
* infix <-- string parsed
809
* te <-- tokenized expression
810
*----------------------------------------------------------------------------*/
813
_dump_tokenized(const char *infix,
814
const _tokenized_t te)
824
for (i = 0; i < te.n_tokens; i++) {
825
bft_printf(" %3d: %-20s", i, te.tokens + te.token_id[i]);
826
bft_printf(" (%d bytes from infix start", te.infix_id[i]);
827
if (te.protected[i] != 0)
828
bft_printf(", protected)\n");
834
/*----------------------------------------------------------------------------
839
*----------------------------------------------------------------------------*/
842
_stack_initialize(_stack_t *stack)
845
stack->max_size = BASE_STACK_SIZE;
846
stack->elements = stack->_elements;
849
/*----------------------------------------------------------------------------
854
*----------------------------------------------------------------------------*/
857
_stack_empty(_stack_t *stack)
860
stack->max_size = BASE_STACK_SIZE;
861
if (stack->elements != stack->_elements) {
862
BFT_FREE(stack->elements);
863
stack->elements = stack->_elements;
867
/*----------------------------------------------------------------------------
868
* Push operator info to the top of the stack
872
* op <-- Pointer to operator definition
873
* token_id <-- associated token id
874
*----------------------------------------------------------------------------*/
878
_stack_push(_stack_t *stack,
879
const _operator_t *op,
884
assert(stack != NULL);
886
if (stack->size >= stack->max_size) {
887
stack->max_size *= 2;
888
if (stack->max_size > BASE_STACK_SIZE) {
889
if (stack->elements == stack->_elements) {
890
BFT_MALLOC(stack->elements, stack->max_size, _stack_entry_t);
891
memcpy(stack->elements, stack->_elements, stack->size*sizeof(_stack_entry_t));
894
BFT_REALLOC(stack->elements, stack->max_size, _stack_entry_t);
898
e = stack->elements + stack->size;
901
e->token_id = token_id;
906
/*----------------------------------------------------------------------------
907
* Pop an entry from the top of the stack
911
* id --> optional id associated with value, or NULL
914
* the value on the top of the stack
915
*----------------------------------------------------------------------------*/
917
inline static _stack_entry_t
918
_stack_pop(_stack_t *stack)
920
assert(stack != NULL);
922
if (stack->size == 0)
923
bft_error(__FILE__, __LINE__, 0,
924
_("Trying to pop an entry from empty stack."));
926
return stack->elements[--(stack->size)];
929
/*----------------------------------------------------------------------------
930
* Return the number of elements in a stack
936
* number of elements in the stack
937
*----------------------------------------------------------------------------*/
940
_stack_size(_stack_t *stack)
945
/*----------------------------------------------------------------------------
946
* Return pointer to operator definition for the entry at the top of
947
* a stack (without modifying the stack)
953
* the value on the top of the stack
954
*----------------------------------------------------------------------------*/
956
inline static const _operator_t *
957
_stack_top(const _stack_t *stack)
959
assert(stack != NULL);
961
if (stack->size == 0)
962
bft_error(__FILE__, __LINE__, 0,
963
_("Querying a top value from empty stack."));
965
return (stack->elements + stack->size - 1)->op;
968
/*----------------------------------------------------------------------------
969
* Initialize a postfix expression
972
* infix <-> initially infix expression
975
* new postfix structure
976
*----------------------------------------------------------------------------*/
978
static fvm_selector_postfix_t *
979
_postfix_create(const char *infix)
982
size_t size = strlen(infix);
983
fvm_selector_postfix_t *pf = NULL;
985
BFT_MALLOC(pf, 1, fvm_selector_postfix_t);
987
pf->coords_dependency = false;
988
pf->normals_dependency = false;
991
pf->max_size = size * sizeof(size_t);
993
BFT_MALLOC(pf->infix, size + 1, char);
994
strcpy(pf->infix, infix);
996
BFT_MALLOC(pf->elements, pf->max_size, unsigned char);
997
for (i = 0; i < pf->max_size; pf->elements[i++] = '\0');
999
pf->n_missing_operands = 0;
1000
pf->missing_operand = NULL;
1005
/*----------------------------------------------------------------------------
1006
* Destroy a postfix expression
1009
* pf <-> pointer to structure pointer that should be destroyed
1010
*----------------------------------------------------------------------------*/
1013
_postfix_destroy(fvm_selector_postfix_t **pf)
1015
fvm_selector_postfix_t *_pf = *pf;
1019
BFT_FREE(_pf->infix);
1020
BFT_FREE(_pf->elements);
1022
if (_pf->n_missing_operands > 0) {
1024
for (i = 0; i < _pf->n_missing_operands; i++)
1025
BFT_FREE(_pf->missing_operand[i]);
1026
BFT_FREE(_pf->missing_operand);
1034
/*----------------------------------------------------------------------------
1035
* Grow postfix string for future additions
1038
* pf <-> posfix string
1039
* size_t <-- new_size
1040
*----------------------------------------------------------------------------*/
1043
_postfix_grow(fvm_selector_postfix_t *pf,
1047
size_t old_max_size = pf->max_size;
1048
if (old_max_size*2 > new_size)
1051
pf->max_size = new_size;
1053
BFT_REALLOC(pf->elements, pf->max_size, unsigned char);
1054
for (i = old_max_size; i < pf->max_size; pf->elements[i++] = '\0');
1057
/*----------------------------------------------------------------------------
1058
* Adjust max size of postfix structure to current size
1061
* pf <-> posfix string
1062
*----------------------------------------------------------------------------*/
1065
_postfix_adjust(fvm_selector_postfix_t *pf)
1067
if (pf->size != pf->max_size) {
1068
pf->max_size = pf->size;
1069
BFT_REALLOC(pf->elements, pf->max_size, unsigned char);
1073
/*----------------------------------------------------------------------------
1074
* Add an operator code to a postfix expression
1077
* pf <-> pointer to postfix structure
1078
* code <-- operator code
1079
*----------------------------------------------------------------------------*/
1082
_postfix_add_opcode(fvm_selector_postfix_t *pf,
1083
_operator_code_t code)
1085
size_t add_size = _postfix_type_size + _postfix_opcode_size;
1087
/* Update postfix */
1089
if (pf->size + add_size > pf->max_size)
1090
_postfix_grow(pf, pf->size + add_size);
1092
*((_postfix_type_t *)(pf->elements + pf->size)) = PF_OPCODE;
1093
*((_operator_code_t *)(pf->elements + pf->size + _postfix_type_size))
1096
pf->size += add_size;
1099
/*----------------------------------------------------------------------------
1100
* Add an integer to a postfix expression
1103
* pf <-> pointer to postfix structure
1104
* val <-- integer value
1105
* type <-- integer subtype (PF_GROUP_ID, PF_ATTRIBUTE_ID, or PF_INT)
1106
*----------------------------------------------------------------------------*/
1109
_postfix_add_int(fvm_selector_postfix_t *pf,
1111
_postfix_type_t type)
1113
size_t add_size = _postfix_type_size + _postfix_int_size;
1115
/* Update postfix */
1117
if (pf->size + add_size > pf->max_size)
1118
_postfix_grow(pf, pf->size + add_size);
1120
*((_postfix_type_t *)(pf->elements + pf->size)) = type;
1121
*((int *)(pf->elements + pf->size + _postfix_type_size)) = val;
1123
pf->size += add_size;
1126
/*----------------------------------------------------------------------------
1127
* Add an float to a postfix expression
1130
* pf <-> pointer to postfix structure
1131
* val <-- integer value
1132
*----------------------------------------------------------------------------*/
1135
_postfix_add_float(fvm_selector_postfix_t *pf,
1138
size_t add_size = _postfix_type_size + _postfix_float_size;
1140
/* Update postfix */
1142
if (pf->size + add_size > pf->max_size)
1143
_postfix_grow(pf, pf->size + add_size);
1145
*((_postfix_type_t *)(pf->elements + pf->size)) = PF_FLOAT;
1146
*((double *)(pf->elements + pf->size + _postfix_type_size)) = val;
1148
pf->size += add_size;
1151
/*----------------------------------------------------------------------------
1152
* Add missing operand to postfix string structure
1155
* pf <-> posfix string
1156
* missing <-- name of missing operand
1157
*----------------------------------------------------------------------------*/
1160
_postfix_add_missing(fvm_selector_postfix_t *pf,
1161
const char *missing)
1163
int n = pf->n_missing_operands;
1165
BFT_REALLOC(pf->missing_operand, n + 1, char *);
1166
BFT_MALLOC(pf->missing_operand[n], strlen(missing) + 1, char);
1167
strcpy(pf->missing_operand[pf->n_missing_operands], missing);
1168
pf->n_missing_operands++;
1171
/*----------------------------------------------------------------------------
1172
* Check if a string defines an integer and scan its value
1175
* str <-- string parsed
1176
* value --> integer conversion
1179
* true if the string defines an integer, false otherwise
1180
*----------------------------------------------------------------------------*/
1183
_is_int(const char *str,
1187
int retcode, int_len;
1190
retcode = (_Bool)(sscanf(str, "%i%n", &_value, &int_len));
1193
if (int_len != (int)strlen(str))
1203
/*----------------------------------------------------------------------------
1204
* Check if a string defines a floating-point number and scan its value
1207
* str <-- string parsed
1208
* value --> floating-point conversion
1211
* true if the string defines a floating-point number, false otherwise
1212
*----------------------------------------------------------------------------*/
1215
_is_float(const char *str,
1219
int retcode, flt_len;
1222
retcode = (_Bool)(sscanf(str, "%f%n", &_value, &flt_len));
1225
if (flt_len != (int)strlen(str))
1235
/*----------------------------------------------------------------------------
1236
* Handle a parsing error.
1239
* err_str <-- error string
1240
* valid_syntax <-- optional valid syntax info, or NULL
1241
* infix <-- string parsed
1242
* te <-- tokenized expression
1243
* token_id <-- token id (or -1 if unknown)
1244
* stack <-> stack (emptied)
1245
* postfix <-> postfix expression (destroyed)
1246
*----------------------------------------------------------------------------*/
1249
_parse_error(const char *err_str,
1250
const char *valid_syntax,
1252
const _tokenized_t *te,
1255
fvm_selector_postfix_t **postfix)
1260
infix_pos = te->infix_id[token_id];
1262
_stack_empty(stack);
1263
_postfix_destroy(postfix);
1265
if (getenv("FVM_SELECTOR_DEBUG")) {
1266
_parser_dump(_parser);
1267
_dump_tokenized(infix, *te);
1270
if (infix_pos > -1) {
1273
char *infix_string_marker = NULL;
1275
BFT_MALLOC(infix_string_marker, infix_pos + 2, char);
1276
for (i = 0; i < infix_pos; i++)
1277
infix_string_marker[i] = ' ';
1278
infix_string_marker[infix_pos] = '^';
1279
infix_string_marker[infix_pos + 1] = '\0';
1281
if (valid_syntax != NULL)
1282
bft_error(__FILE__, __LINE__, 0,
1283
_("Error parsing expression:\n"
1287
"Valid (expected) syntax:\n\n"
1289
infix, infix_string_marker, err_str, valid_syntax);
1291
bft_error(__FILE__, __LINE__, 0,
1292
_("Error parsing expression:\n"
1296
infix, infix_string_marker, err_str);
1298
BFT_FREE(infix_string_marker);
1303
if (valid_syntax != NULL)
1304
bft_error(__FILE__, __LINE__, 0,
1305
_("Error parsing expression:\n"
1308
"Valid (expected) syntax:\n\n"
1310
infix, err_str, valid_syntax);
1312
bft_error(__FILE__, __LINE__, 0,
1313
_("Error parsing expression:\n"
1321
/*----------------------------------------------------------------------------
1322
* Check for left / right operands for unary or binary operators
1325
* infix <-- string parsed
1326
* te <-- tokenized expression
1327
* token_id <-- token id in tokenized expression
1328
* otype <-- type of operator
1329
* has_r_operand <-- does the operator have a right operand ?
1330
* os <-- operator stack (for clean-up in case of error)
1331
* postfix <-> postfix expression (destroyed)
1332
*----------------------------------------------------------------------------*/
1335
_check_left_right(const char *infix,
1336
const _tokenized_t *te,
1338
_operator_type_t otype,
1339
_Bool has_r_operand,
1341
fvm_selector_postfix_t **postfix)
1345
if (otype != OT_L_PAREN && otype != OT_UNARY && otype != OT_BINARY)
1350
if ( i == te->n_tokens
1351
|| ( te->protected[i] == false
1352
&& te->tokens[te->token_id[i]] == ')'))
1353
_parse_error(_("Operator needs a right operand."),
1354
NULL, infix, te, token_id, os, postfix);
1356
if (otype == OT_BINARY && has_r_operand == false)
1357
_parse_error(_("Operator needs a left operand."),
1358
NULL, infix, te, token_id, os, postfix);
1359
else if ((otype == OT_L_PAREN || otype == OT_UNARY) && has_r_operand == true)
1360
_parse_error(_("Operator should not have a left operand."),
1361
NULL, infix, te, token_id, os, postfix);
1364
/*----------------------------------------------------------------------------
1365
* Find a group or attribute corresponding to a token
1368
* n_groups <-- number of groups
1369
* n_attributes <-- number of attributes
1370
* group_name <-- array group names (sorted)
1371
* attribute <-- array of attribute numbers (sorted)
1372
* token <-- token (string) to associated with group or attribute
1373
* protected <-- is token protected (i.e. not interpretable) ?
1374
* group_id --> -1, or id of group corresponding to token
1375
* attribute_id --> -1, or id of attribute corresponding to token
1376
*----------------------------------------------------------------------------*/
1379
_find_group_or_attribute(int n_groups,
1381
const char *group_name[],
1382
const int attribute[],
1388
int att_cmp, start_id, end_id;
1390
/* Initialize return values */
1395
/* Test for attributes first */
1397
if (protected == false) {
1401
if (_is_int(token, &val) && n_attributes > 0) {
1404
end_id = n_attributes - 1;
1406
/* use binary search */
1408
while (start_id <= end_id) {
1409
int mid_id = start_id + ((end_id - start_id) / 2);
1410
att_cmp = attribute[mid_id];
1412
start_id = mid_id + 1;
1413
else if (att_cmp > val)
1414
end_id = mid_id - 1;
1416
*attribute_id = mid_id;
1426
/* Test for groups if no attributes found */
1432
end_id = n_groups - 1;
1434
/* use binary search */
1436
while (start_id <= end_id) {
1437
int mid_id = start_id + ((end_id - start_id) / 2);
1438
att_cmp = strcmp(group_name[mid_id], token);
1440
start_id = mid_id + 1;
1441
else if (att_cmp > 0)
1442
end_id = mid_id - 1;
1450
/*----------------------------------------------------------------------------
1451
* Determine if tokens define a group range
1454
* n_groups <-- number of groups
1455
* group_name <-- array of group names (sorted)
1456
* token <-> tokens (string) associated with groups
1457
* group_id --> -1, or id of group corresponding to token
1458
*----------------------------------------------------------------------------*/
1461
_group_range(int n_groups,
1462
const char *group_name[],
1463
const char *token[2],
1466
int i, att_cmp, start_id, end_id, mid_id;
1468
/* Initialize return values */
1473
/* Test for groups */
1477
if (strcmp(token[0], token[1]) > 0) {
1478
const char *_tmp = token[0];
1479
token[0] = token[1];
1483
for (i = 0; i < 2; i++) {
1486
end_id = n_groups - 1;
1487
mid_id = (end_id - start_id) / 2;
1489
/* use binary search */
1491
while (start_id < end_id) {
1492
att_cmp = strcmp(group_name[mid_id], token[i]);
1494
start_id = mid_id + 1;
1495
else if (att_cmp > 0)
1496
end_id = mid_id - 1;
1499
mid_id = start_id + ((end_id - start_id) / 2);
1502
att_cmp = strcmp(group_name[mid_id], token[i]);
1503
group_id[i] = mid_id;
1504
if (i == 0 && att_cmp < 0)
1505
group_id[i] = mid_id + 1;
1506
else if (i == 1 && att_cmp > 0)
1507
group_id[i] = mid_id - 1;
1511
if ( group_id[0] >= n_groups
1512
|| group_id[1] < 0) {
1516
else if (group_id[1] >= n_groups)
1523
/*----------------------------------------------------------------------------
1524
* Determine if tokens define an atribute range
1527
* n_attributes <-- number of attributes
1528
* attribute <-- array of attribute numbers (sorted)
1529
* token <-- tokens (string) associated with attributes
1530
* attribute_id --> -1, or id of attribute corresponding to token
1531
*----------------------------------------------------------------------------*/
1534
_attribute_range(int n_attributes,
1535
const int attribute[],
1536
const char *token[2],
1537
int attribute_id[2])
1539
int i, att_cmp, start_id, end_id, mid_id;
1542
/* Initialize return values */
1544
attribute_id[0] = -1;
1545
attribute_id[1] = -1;
1547
/* Test for attributes */
1549
if ( n_attributes > 0
1550
&& _is_int(token[0], val) && _is_int(token[1], val + 1)) {
1552
if (val[0] > val[1]) {
1558
for (i = 0; i < 2; i++) {
1561
end_id = n_attributes - 1;
1562
mid_id = (end_id - start_id) / 2;
1564
/* use binary search */
1566
while (start_id < end_id) {
1567
att_cmp = attribute[mid_id];
1568
if (att_cmp < val[i])
1569
start_id = mid_id + 1;
1570
else if (att_cmp > val[i])
1571
end_id = mid_id - 1;
1574
mid_id = start_id + ((end_id - start_id) / 2);
1577
attribute_id[i] = mid_id;
1578
if (i == 0 && attribute[mid_id] < val[i])
1579
attribute_id[i] = mid_id + 1;
1580
else if (i == 1 && attribute[mid_id] > val[i])
1581
attribute_id[i] = mid_id - 1;
1585
if ( attribute_id[0] >= n_attributes
1586
|| attribute_id[1] < 0) {
1587
attribute_id[0] = -1;
1588
attribute_id[1] = -1;
1590
else if (attribute_id[1] >= n_attributes)
1591
attribute_id[1] -= 1;
1597
/*----------------------------------------------------------------------------
1598
* Handle geometric functions in a tokenized expression.
1601
* opcode <-- operator code
1602
* infix <-- string parsed
1603
* te <-- tokenized expression
1604
* token_start <-> start id in tokenized expression
1605
* token_end t <-> past the-end id in tokenized expression
1606
* os <-> operator stack
1607
* postfix <-> pointer to postfix expression,
1608
*----------------------------------------------------------------------------*/
1611
_parse_geometric_args(_operator_code_t opcode,
1613
const _tokenized_t *te,
1617
fvm_selector_postfix_t **postfix)
1620
int i = token_start;
1622
int n_vals = 0, n_opts = 0;
1623
double val[13]; /* 12 values max for box(x0, dx, dy, dz),
1624
1 extra slot for error checking */
1625
int inout = 0; /* 0: undefined; -1: inside; 1: outside */
1626
double epsilon = 1.e-2, norm = 1.0;
1627
_Bool error = false;
1628
_Bool have_epsilon = false;
1630
const char *func_syntax = NULL;
1631
const char *normals_syntax
1632
= N_(" normal[<x>, <y>, <z>, <epsilon>]\n"
1633
" normal[<x>, <y>, <z>, epsilon = <epsilon>]");
1634
const char *plane_syntax
1635
= N_(" For ax + by + cz + d = 0 form:\n\n"
1636
" plane[<a>, <b>, <c>, <d>, <epsilon>]\n"
1637
" plane[<a>, <b>, <c>, <d>, epsilon = <epsilon>]\n"
1638
" plane[<a>, <b>, <c>, <d>, inside]\n"
1639
" plane[<a>, <b>, <c>, <d>, outside]\n\n"
1640
" For {normal, point in plane} form:\n\n"
1641
" plane[<nx>, <ny>, <nz>, <x>, <y>, <z>, <epsilon>]\n"
1642
" plane[<nx>, <ny>, <nz>, <x>, <y>, <z>, epsilon = <epsilon>]\n"
1643
" plane[<nx>, <ny>, <nz>, <x>, <y>, <z>, inside]\n"
1644
" plane[<nx>, <ny>, <nz>, <x>, <y>, <z>, outside]");
1645
const char *box_syntax
1646
= N_(" For x_min, y_min, z_min, x_max, y_max, z_max form:\n\n"
1647
" box[<xmin>, <ymin>, <zmin>, <xmax>, <ymax>, <zmax>]\n\n"
1648
" For xyz_0, dxyz_1, dxyz_2, dxyz_3 form:\n\n"
1649
" box[<x0>, <y0>, <z0>, <dx1>, <dy1>, <dz1>\n"
1650
" <dx2>, <dy2>, <dz2>, <dx3>, <dy3>, <dz3>]");
1651
const char *cylinder_syntax
1652
= N_(" cylinder[<x0>, <y0>, <z0>, <x1>, <y1>, <z1>, <radius>]");
1653
const char *sphere_syntax
1654
= N_(" sphere[<xc>, <yc>, <zc>, <radius>]");
1656
/* First parse for floating-point values */
1658
while (i < token_end && error == false) {
1660
tok = te->tokens + te->token_id[i];
1662
if (_is_float(tok, val + n_vals)) {
1663
tok = te->tokens + te->token_id[++i];
1666
error = true; /* Will be handled depending on opcode */
1667
else if (i < token_end && strcmp(te->tokens + te->token_id[i], ",")) {
1668
_parse_error(_("Missing or wrong argument separator."),
1669
NULL, infix, te, i, os, postfix);
1680
if (i == token_end && *(te->tokens + te->token_id[i-1]) == ',')
1681
_parse_error(_("Missing argument after separator."),
1682
NULL, infix, te, i, os, postfix);
1684
/* Initialize error reporting function syntax,
1685
check number of floating-point arguments,
1686
and normalize normals. */
1691
func_syntax = normals_syntax;
1693
have_epsilon = true;
1694
epsilon = val[n_vals-1];
1699
norm = sqrt(val[0]*val[0] + val[1]*val[1] + val[2]*val[2]);
1700
val[0] /= norm; val[1] /= norm; val[2] /= norm;
1704
func_syntax = plane_syntax;
1705
if (n_vals == 5 || n_vals == 7) {
1706
have_epsilon = true;
1707
epsilon = val[n_vals-1];
1710
if (n_vals != 4 && n_vals != 6)
1712
norm = sqrt(val[0]*val[0] + val[1]*val[1] + val[2]*val[2]);
1713
val[0] /= norm; val[1] /= norm; val[2] /= norm;
1714
/* Normalize d in ax + by + cz + d form, or convert to this form */
1717
else { /* if (n_vals == 6) */
1718
val[3] = - (val[0]*val[3] + val[1]*val[4] + val[2]*val[5]);
1724
func_syntax = box_syntax;
1725
if (n_vals != 6 && n_vals != 12)
1730
func_syntax = cylinder_syntax;
1736
func_syntax = sphere_syntax;
1742
_parse_error(_("This geometric function is not implemented."),
1743
NULL, infix, te, token_start - 2, os, postfix);
1748
_parse_error(_("Wrong number of floating-point arguments."),
1750
infix, te, token_start, os, postfix);
1752
/* Check for one additional (key, value) arguments */
1754
if (i < token_end && error == false) {
1756
if ((opcode == OC_NORMAL || opcode == OC_PLANE) && have_epsilon == false) {
1758
if (strcmp(te->tokens + te->token_id[i], "epsilon") == 0) {
1759
if (strcmp(te->tokens + te->token_id[i+1], "="))
1761
tok = te->tokens + te->token_id[i+2];
1762
if (_is_float(tok, &epsilon)) {
1763
have_epsilon = true;
1767
_parse_error(_("Expected syntax:\n"
1768
" epsilon = <value>\n"),
1769
NULL, infix, te, i, os, postfix);
1776
if (opcode == OC_PLANE && have_epsilon == false) {
1777
if (strcmp(te->tokens + te->token_id[i], "inside") == 0) {
1781
else if (strcmp(te->tokens + te->token_id[i], "outside") == 0) {
1789
if (i < token_end) {
1790
_parse_error(_("Unexpected argument(s)."),
1792
infix, te, i, os, postfix);
1795
/* Update postfix */
1797
if (opcode == OC_NORMAL) {
1798
(*postfix)->normals_dependency = true;
1799
/* sign*square of cosine compared to square of (1-epsilon) */
1800
val[n_vals++] = (1 - 2*epsilon + epsilon*epsilon);
1801
assert(n_vals == 4);
1804
(*postfix)->coords_dependency = true;
1805
if (opcode == OC_PLANE) {
1807
val[n_vals++] = epsilon;
1810
assert(n_vals + n_opts == 5);
1814
_postfix_add_opcode(*postfix, opcode);
1815
_postfix_add_int(*postfix, n_vals + n_opts, PF_INT);
1816
for (i = 0; i < n_vals; i++)
1817
_postfix_add_float(*postfix, val[i]);
1819
assert (opcode == OC_PLANE && inout != 0);
1820
_postfix_add_int(*postfix, inout, PF_INT);
1825
/*----------------------------------------------------------------------------
1826
* Check for and handle coordinate conditions in a tokenized expression.
1829
* this_parser <-- parser object
1830
* infix <-- string parsed
1831
* te <-- tokenized expression
1832
* n_groups <-- number of groups
1833
* n_attributes <-- number of attributes
1834
* group_name <-- array group names (sorted)
1835
* attribute <-- array of attribute numbers (sorted)
1836
* token_id <-> current token id in tokenized expression
1837
* has_r_operand <-> indicates if the current token has a right operand
1838
* os <-> operator stack
1839
* postfix <-> pointer to postfix expression,
1840
*----------------------------------------------------------------------------*/
1843
_parse_for_function(const _parser_t *this_parser,
1845
const _tokenized_t *te,
1848
const char *group_name[],
1849
const int attribute[],
1851
_Bool *has_r_operand,
1853
fvm_selector_postfix_t **postfix)
1856
int i = *token_id + 1, j = 0, k = 0;
1857
const _operator_t *op = NULL;
1859
if (te->n_tokens <= i)
1862
tok = te->tokens + te->token_id[i];
1864
/* Pre-check syntax */
1866
if (te->protected[i] == true || strlen(tok) != 1)
1872
/* If we arrived here, we have a function start */
1875
for (j = i + 1; j < te->n_tokens; j++) {
1876
tok = te->tokens + te->token_id[j];
1877
if (te->protected[j] == false && strlen(tok) == 1) {
1880
else if (tok[0] == ']')
1886
if (j == te->n_tokens) {
1887
_parse_error(_("Missing closing ]."),
1888
NULL, infix, te, i, os, postfix);
1892
/* We have a function-type syntax, so find the corresponding function */
1894
tok = te->tokens + te->token_id[*token_id];
1896
if (te->protected[i] == false) {
1897
for (k = 0; k < this_parser->n_keywords; k++) {
1898
if (strcmp(tok, this_parser->keyword[k]) == 0) {
1899
op = this_parser->operators + this_parser->keyword_op_id[k];
1906
_parse_error(_("Function arguments used with an unknown operator."),
1907
NULL, infix, te, *token_id, os, postfix);
1910
else if (op->type != OT_FUNCTION) {
1911
_parse_error(_("Operator does not accept function arguments."),
1912
NULL, infix, te, *token_id, os, postfix);
1917
*has_r_operand = true;
1919
/* Handle general group selection operators */
1921
if (op->code == OC_ALL || op->code == OC_NO_GROUP) {
1923
_parse_error(_("Function requires 0 arguments."),
1924
NULL, infix, te, *token_id, os, postfix);
1926
_postfix_add_opcode(*postfix, op->code);
1929
/* Handle range operator */
1931
else if (op->code == OC_RANGE) {
1933
const char *t[3] = {NULL, NULL, NULL};
1934
_Bool force_group = false, force_attrib = false, error = false;
1938
while (i < j && k < 3) {
1939
t[k++] = te->tokens + te->token_id[i];
1942
if (strcmp(te->tokens + te->token_id[i], ","))
1955
if (strcmp(t[2], "group") == 0)
1957
else if (strcmp(t[2], "attribute") == 0)
1958
force_attrib = true;
1964
if (k != 2 || error)
1965
_parse_error(_("range[] argument error"),
1966
_(" range[<first>, <last>]\n"
1967
" range[<first>, <last>, group]\n"
1968
" range[<first>, <last>, attribute]"),
1969
infix, te, i - 1, os, postfix);
1973
int ga_id[2] = {-1, -1};
1974
_postfix_type_t pf_type = PF_GROUP_ID;
1975
if (force_group == false)
1976
_attribute_range(n_attributes, attribute, t, ga_id);
1977
if (force_attrib == true || ga_id[0] > -1)
1978
pf_type = PF_ATTRIBUTE_ID;
1980
_group_range(n_groups, group_name, t, ga_id);
1981
if (ga_id[0] > -1) {
1982
_postfix_add_opcode(*postfix, op->code);
1983
_postfix_add_int(*postfix, ga_id[0], pf_type);
1984
_postfix_add_int(*postfix, ga_id[1], pf_type);
1987
_postfix_add_int(*postfix, -1, pf_type);
1988
_postfix_add_missing(*postfix, t[0]);
1989
_postfix_add_missing(*postfix, t[1]);
1995
/* Handle geometric operators */
1998
_parse_geometric_args(op->code, infix, te, i+1, j, os, postfix);
2002
/*----------------------------------------------------------------------------
2003
* Check for and handle coordinate conditions in a tokenized expression.
2006
* infix <-- string parsed
2007
* te <-- tokenized expression
2008
* token id <-> current token id in tokenized expression
2009
* has_r_operand <-> indicates if the current token has a right operand
2010
* os <-> operator stack
2011
* postfix <-> pointer to postfix expression,
2012
*----------------------------------------------------------------------------*/
2015
_parse_for_coord_conditions(const char *infix,
2016
const _tokenized_t *te,
2018
_Bool *has_r_operand,
2020
fvm_selector_postfix_t **postfix)
2025
_Bool has_coord_cond = false;
2027
int i = *token_id + 1, j = 0;
2029
if (te->n_tokens <= i)
2032
t1 = te->tokens + te->token_id[i];
2033
t1_len = strlen(t1);
2035
/* Pre-check syntax */
2037
if (te->protected[i] == true || t1_len == 0 || t1_len > 2)
2040
if ((t1[0] != '<' && t1[0] != '>') || (t1_len == 2 && t1[1] != '='))
2043
/* If we arrived here, we have a >, <, >=, or <= operator */
2045
if (te->n_tokens == i+1) {
2046
_parse_error(_("Operator needs a right operand."),
2047
NULL, infix, te, i, os, postfix);
2051
/* Try for coord_id, operator, value or value, operator, coord_id */
2053
for (j = 0; j < 2; j++) {
2055
const char *t2 = te->tokens + te->token_id[i - 1 + j*2];
2057
if (strlen(t2) == 1) {
2058
if (*t2 == 'x' || *t2 == 'X')
2060
else if (*t2 == 'y' || *t2 == 'Y')
2062
else if (*t2 == 'z' || *t2 == 'Z')
2070
has_coord_cond = _is_float(te->tokens + te->token_id[i + 1], &val);
2072
has_coord_cond = _is_float(te->tokens + te->token_id[i - 1], &val);
2074
/* If we have a valid syntax, add it to postfix */
2076
if (has_coord_cond) {
2078
_operator_code_t oc;
2080
/* Permute operator if necessery to always have a
2081
{coord_id, operator, value} expression */
2103
_postfix_add_opcode(*postfix, oc);
2104
_postfix_add_int(*postfix, coord_id, PF_INT);
2105
_postfix_add_float(*postfix, val);
2109
*has_r_operand = true;
2110
(*postfix)->coords_dependency = true;
2114
_parse_error(_("Operator needs a floating point operand\n"
2115
"on one side, x, y, or z on the other"),
2116
NULL, infix, te, i, os, postfix);
2120
/* If we have a valid syntax with the coord_id on the
2121
left, we may have a "1 < x <= 2" type syntax */
2123
if (has_coord_cond && j == 1 && te->n_tokens > i) {
2125
const char *t3 = te->tokens + te->token_id[i];
2126
size_t t3_len = strlen(t3);
2128
if (te->protected[i] == true || t3_len == 0 || t3_len > 2)
2131
if ( (t3[0] != '<' && t3[0] != '>')
2132
|| (t3_len == 2 && t3[1] != '='))
2135
if (t3[0] != t1[0]) {
2136
_parse_error(_("Inconsistant interval specification."),
2137
NULL, infix, te, i, os, postfix);
2140
else if (te->n_tokens == i+1) {
2141
_parse_error(_("Operator needs a right operand."),
2142
NULL, infix, te, i, os, postfix);
2146
has_coord_cond = _is_float(te->tokens + te->token_id[i + 1], &val);
2148
/* If we have a valid syntax, add it to postfix */
2150
if (has_coord_cond) {
2152
_operator_code_t oc;
2154
/* No permutation necessary here */
2167
_postfix_add_opcode(*postfix, oc);
2168
_postfix_add_int(*postfix, coord_id, PF_INT);
2169
_postfix_add_float(*postfix, val);
2171
/* Add implicit and here */
2173
_postfix_add_opcode(*postfix, OC_AND);
2180
_parse_error(_("Operator needs a floating point operand"),
2181
NULL, infix, te, i, os, postfix);
2188
/*----------------------------------------------------------------------------
2189
* Parse a tokenized expression string.
2192
* this_parser <-- parser object
2193
* infix <-- string parsed
2194
* te <-- tokenized expression
2195
* n_groups <-- number of groups
2196
* n_attributes <-- number of attributes
2197
* group_name <-- array group names (sorted)
2198
* attribute <-- array of attribute numbers (sorted)
2201
* pointer to created postfix structure
2202
*----------------------------------------------------------------------------*/
2204
static fvm_selector_postfix_t *
2205
_parse_tokenized(const _parser_t *this_parser,
2207
const _tokenized_t *te,
2210
const char *group_name[],
2211
const int attribute[])
2215
_Bool has_r_operand = false;
2216
fvm_selector_postfix_t *pf = NULL;
2218
/* Initialization */
2220
_stack_initialize(&os);
2222
pf = _postfix_create(infix);
2224
/* Loop on tokens */
2228
while (i < te->n_tokens) {
2231
const _operator_t *op_1 = NULL;
2233
/* Look ahead to handle functions and "<", "<=", ">", ">=" syntax */
2235
_parse_for_function(this_parser,
2246
_parse_for_coord_conditions(infix, te, &i, &has_r_operand, &os, &pf);
2248
if (i == te->n_tokens)
2251
/* Now handle token */
2253
tok = te->tokens + te->token_id[i];
2255
if (te->protected[i] == false) {
2256
for (j = 0; j < this_parser->n_keywords; j++) {
2257
if (strcmp(tok, this_parser->keyword[j]) == 0) {
2258
op_1 = this_parser->operators + this_parser->keyword_op_id[j];
2264
/* Basic check for left / right operands to operators */
2267
_check_left_right(infix, te, i, op_1->type, has_r_operand, &os, &pf);
2269
/* Now add to postfix or stack */
2273
int group_id, attribute_id;
2275
/* If two operands follow each other, we have a parse error */
2277
if (has_r_operand == true)
2278
_parse_error(_("Expected operator instead of operand."),
2279
NULL, infix, te, i, &os, &pf);
2281
/* Now add entry to postfix */
2283
_find_group_or_attribute(n_groups,
2292
if (attribute_id > -1)
2293
_postfix_add_int(pf, attribute_id, PF_ATTRIBUTE_ID);
2295
_postfix_add_int(pf, group_id, PF_GROUP_ID);
2297
if (attribute_id == -1 && group_id == -1)
2298
_postfix_add_missing(pf, tok);
2303
switch(op_1->type) {
2306
_stack_push(&os, op_1, i);
2311
const _operator_t *op_2 = NULL;
2312
_Bool matched = false;
2313
while (_stack_size(&os) > 0) {
2314
_stack_entry_t e = _stack_pop(&os);
2316
if (op_2->type == OT_L_PAREN) {
2321
_postfix_add_opcode(pf, op_2->code);
2324
if (matched == false)
2325
_parse_error(_("Parenthesis mismatch"),
2326
NULL, infix, te, i, &os, &pf);
2330
/* At this stage, a function or "<", "<=", ">", ">=" syntax should
2331
have been handled, so we have a syntax error here*/
2333
case OT_COORD_CONDITION:
2335
_parse_error(_("Syntax error, probably due to misplaced operands."),
2336
NULL, infix, te, i, &os, &pf);
2341
while (_stack_size(&os) > 0) {
2342
const _operator_t *op_2 = _stack_top(&os);
2343
if (op_1->priority < op_2->priority) {
2344
_stack_entry_t e = _stack_pop(&os);
2345
_postfix_add_opcode(pf, (e.op)->code);
2350
_stack_push(&os, op_1, i);
2352
} /* End of switch on operator type */
2358
has_r_operand = true;
2360
if (op_1->type != OT_R_PAREN && op_1->type != OT_FUNCTION)
2361
has_r_operand = false;
2364
} /* End of loop on tokens */
2366
while (_stack_size(&os) > 0) {
2368
_stack_entry_t e = _stack_pop(&os);
2369
const _operator_t *op = e.op;
2371
if (op->type == OT_L_PAREN)
2372
_parse_error(_("Parenthesis mismatch"),
2373
NULL, infix, te, e.token_id, &os, &pf);
2375
_postfix_add_opcode(pf, op->code);
2380
_postfix_adjust(pf);
2385
/*----------------------------------------------------------------------------
2386
* Evaluate normal[] function conditions in a postfix expression
2389
* pf <-- pointer to postfix structure
2390
* normal <-- normal associated with evaluation
2391
* i <-> current position in expression being evaluated
2394
* true or false depending on evaluation
2395
*----------------------------------------------------------------------------*/
2398
_eval_normal(const fvm_selector_postfix_t *pf,
2399
const double normal[],
2405
const int n_vals = 4; /* 3 values for coordinates, 1 for tolerance */
2406
_Bool retval = false;
2408
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2409
assert(*((int *)(pf->elements + *i + _postfix_type_size)) == n_vals);
2411
*i += _postfix_type_size + _postfix_int_size + _postfix_type_size;
2413
for (j = 0; j < n_vals; j++) {
2414
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2416
val[j] = *((double *)(pf->elements + *i));
2417
*i += _postfix_float_size + _postfix_type_size;
2419
*i -= _postfix_type_size;
2421
dotp = normal[0]*val[0] + normal[1]*val[1] + normal[2]*val[2];
2424
double cos2 = dotp*dotp / ( normal[0]*normal[0]
2425
+ normal[1]*normal[1]
2426
+ normal[2]*normal[2]);
2434
/*----------------------------------------------------------------------------
2435
* Evaluate plane[] function conditions in a postfix expression
2438
* pf <-- pointer to postfix structure
2439
* coords <-- coordinates associated with evaluation
2440
* i <-> current position in expression being evaluated
2443
* true or false depending on evaluation
2444
*----------------------------------------------------------------------------*/
2447
_eval_plane(const fvm_selector_postfix_t *pf,
2448
const double coords[],
2454
_postfix_type_t pf_type;
2455
_Bool retval = false;
2457
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2458
assert(*((int *)(pf->elements + *i + _postfix_type_size)) == 5);
2460
/* 4 first arguments are always floating-point
2461
(plane equation coefficients) */
2463
*i += _postfix_type_size + _postfix_int_size + _postfix_type_size;
2464
for (j = 0; j < 4; j++) {
2465
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2467
val[j] = *((double *)(pf->elements + *i));
2468
*i += _postfix_float_size + _postfix_type_size;
2470
*i -= _postfix_type_size;
2472
pfunc = val[0]*coords[0] + val[1]*coords[1] + val[2]*coords[2] + val[3];
2474
/* Last argument may be floating-point or interger */
2476
pf_type = *((_postfix_type_t *)(pf->elements + *i));
2477
*i += _postfix_type_size;
2479
if (pf_type == PF_INT) {
2480
int inout = *((int *)(pf->elements + *i));
2481
*i += _postfix_int_size;
2482
assert(inout == -1 || inout == 1);
2483
if ( (inout == -1 && pfunc <= 0)
2484
|| (inout == 1 && pfunc >= 0))
2488
double epsilon = *((double *)(pf->elements + *i));
2489
assert(pf_type == PF_FLOAT);
2490
*i += _postfix_float_size;
2491
if (FVM_ABS(pfunc) < epsilon)
2498
/*----------------------------------------------------------------------------
2499
* Evaluate box[] function conditions in a postfix expression
2502
* pf <-- pointer to postfix structure
2503
* coords <-- coordinates associated with evaluation
2504
* i <-> current position in expression being evaluated
2507
* true or false depending on evaluation
2508
*----------------------------------------------------------------------------*/
2511
_eval_box(const fvm_selector_postfix_t *pf,
2512
const double coords[],
2517
int n_vals; /* number of box coefficients */
2518
_Bool retval = false;
2520
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2521
n_vals = *((int *)(pf->elements + *i + _postfix_type_size));
2522
assert(n_vals == 6 || n_vals == 12);
2524
/* all arguments are floating-point */
2526
*i += _postfix_type_size + _postfix_int_size + _postfix_type_size;
2527
for (j = 0; j < n_vals; j++) {
2528
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2530
val[j] = *((double *)(pf->elements + *i));
2531
*i += _postfix_float_size + _postfix_type_size;
2533
*i -= _postfix_type_size;
2535
/* Geometric test */
2538
if ( val[0] <= coords[0] && val[1] <= coords[1] && val[2] <= coords[2]
2539
&& val[3] >= coords[0] && val[4] >= coords[1] && val[5] >= coords[2])
2543
double _coords[3], l12, l22, l32, dp1, dp2, dp3;
2544
_coords[0] = coords[0] - val[0];
2545
_coords[1] = coords[1] - val[1];
2546
_coords[2] = coords[2] - val[2];
2547
l12 = val[3]*val[3] + val[4]*val[4] + val[5]*val[5];
2548
l22 = val[6]*val[6] + val[7]*val[7] + val[8]*val[8];
2549
l32 = val[9]*val[9] + val[10]*val[10] + val[11]*val[11];
2550
dp1 = _coords[0]*val[3] + _coords[1]*val[4] + _coords[2]*val[5];
2551
dp2 = _coords[0]*val[6] + _coords[1]*val[7] + _coords[2]*val[8];
2552
dp3 = _coords[0]*val[9] + _coords[1]*val[10] + _coords[2]*val[11];
2553
if ( dp1 >= 0 && dp2 >= 0 && dp3 >= 0
2554
&& dp1 <= l12 && dp2 <= l22 && dp3 <= l32)
2561
/*----------------------------------------------------------------------------
2562
* Evaluate cylinder[] function conditions in a postfix expression
2565
* pf <-- pointer to postfix structure
2566
* coords <-- coordinates associated with evaluation
2567
* i <-> current position in expression being evaluated
2570
* true or false depending on evaluation
2571
*----------------------------------------------------------------------------*/
2574
_eval_cylinder(const fvm_selector_postfix_t *pf,
2575
const double coords[],
2580
const int n_vals = 7; /* number of cylinder coefficients */
2581
_Bool retval = false;
2583
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2584
assert(*((int *)(pf->elements + *i + _postfix_type_size)) == n_vals);
2586
/* all arguments are floating-point */
2588
*i += _postfix_type_size + _postfix_int_size + _postfix_type_size;
2589
for (j = 0; j < n_vals; j++) {
2590
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2592
val[j] = *((double *)(pf->elements + *i));
2593
*i += _postfix_float_size + _postfix_type_size;
2595
*i -= _postfix_type_size;
2597
/* Geometric test */
2600
double _coords[3], _axis[3], dotp, len2;
2601
_coords[0] = coords[0] - val[0];
2602
_coords[1] = coords[1] - val[1];
2603
_coords[2] = coords[2] - val[2];
2604
_axis[0] = val[3] - val[0];
2605
_axis[1] = val[4] - val[1];
2606
_axis[2] = val[5] - val[2];
2607
dotp = _coords[0]*_axis[0] + _coords[1]*_axis[1] + _coords[2]*_axis[2];
2608
len2 = _axis[0]*_axis[0] + _axis[1]*_axis[1] + _axis[2]*_axis[2];
2609
if (dotp >= 0 && dotp <= len2) {
2610
double _proj[3], r2;
2611
double mult = dotp / len2;
2612
_proj[0] = _coords[0] - mult*_axis[0];
2613
_proj[1] = _coords[1] - mult*_axis[1];
2614
_proj[2] = _coords[2] - mult*_axis[2];
2615
r2 = _proj[0]*_proj[0] + _proj[1]*_proj[1] + _proj[2]*_proj[2];
2616
if (r2 <= val[6]*val[6])
2624
/*----------------------------------------------------------------------------
2625
* Evaluate sphere[] function conditions in a postfix expression
2628
* pf <-- pointer to postfix structure
2629
* coords <-- coordinates associated with evaluation
2630
* i <-> current position in expression being evaluated
2633
* true or false depending on evaluation
2634
*----------------------------------------------------------------------------*/
2637
_eval_sphere(const fvm_selector_postfix_t *pf,
2638
const double coords[],
2643
const int n_vals = 4; /* number of sphere coefficients */
2644
_Bool retval = false;
2646
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2647
assert(*((int *)(pf->elements + *i + _postfix_type_size)) == n_vals);
2649
/* all arguments are floating-point */
2651
*i += _postfix_type_size + _postfix_int_size + _postfix_type_size;
2652
for (j = 0; j < n_vals; j++) {
2653
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2655
val[j] = *((double *)(pf->elements + *i));
2656
*i += _postfix_float_size + _postfix_type_size;
2658
*i -= _postfix_type_size;
2660
/* Geometric test */
2663
double _coords[3], len2;
2664
_coords[0] = coords[0] - val[0];
2665
_coords[1] = coords[1] - val[1];
2666
_coords[2] = coords[2] - val[2];
2668
= _coords[0]*_coords[0] + _coords[1]*_coords[1] + _coords[2]*_coords[2];
2669
if (len2 <= val[3]*val[3])
2676
/*----------------------------------------------------------------------------
2677
* Evaluate coordinate conditions in a postfix expression
2680
* pf <-- pointer to postfix structure
2681
* coords <-- coordinates associated with evaluation
2682
* i <-> current position in expression being evaluated
2685
* true or false depending on evaluation
2686
*----------------------------------------------------------------------------*/
2689
_eval_coord_gt(const fvm_selector_postfix_t *pf,
2690
const double coords[],
2695
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2696
*i += _postfix_type_size;
2697
coord_id = *((int *)(pf->elements + *i));
2698
*i += _postfix_int_size + _postfix_type_size;
2699
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2701
cmp_val = *((double *)(pf->elements + *i));
2702
*i += _postfix_float_size;
2703
return (coords[coord_id] > cmp_val ? true : false);
2707
_eval_coord_lt(const fvm_selector_postfix_t *pf,
2708
const double coords[],
2713
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2714
*i += _postfix_type_size;
2715
coord_id = *((int *)(pf->elements + *i));
2716
*i += _postfix_int_size + _postfix_type_size;
2717
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2719
cmp_val = *((double *)(pf->elements + *i));
2720
*i += _postfix_float_size;
2721
return (coords[coord_id] < cmp_val ? true : false);
2725
_eval_coord_ge(const fvm_selector_postfix_t *pf,
2726
const double coords[],
2731
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2732
*i += _postfix_type_size;
2733
coord_id = *((int *)(pf->elements + *i));
2734
*i += _postfix_int_size + _postfix_type_size;
2735
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2737
cmp_val = *((double *)(pf->elements + *i));
2738
*i += _postfix_float_size;
2739
return (coords[coord_id] >= cmp_val ? true : false);
2743
_eval_coord_le(const fvm_selector_postfix_t *pf,
2744
const double coords[],
2749
assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
2750
*i += _postfix_type_size;
2751
coord_id = *((int *)(pf->elements + *i));
2752
*i += _postfix_int_size + _postfix_type_size;
2753
assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
2755
cmp_val = *((double *)(pf->elements + *i));
2756
*i += _postfix_float_size;
2757
return (coords[coord_id] <= cmp_val ? true : false);
2760
/*============================================================================
2761
* Public function definitions
2762
*============================================================================*/
2764
/*----------------------------------------------------------------------------
2765
* Create a postfix expression from an infix expression
2768
* infix <-- infix expression
2769
* n_groups <-- number of groups
2770
* n_attributes <-- number of attributes
2771
* group_name <-- array group names (sorted)
2772
* attribute <-- array of attribute numbers (sorted)
2775
* pointer to created postfix structure
2776
*----------------------------------------------------------------------------*/
2778
fvm_selector_postfix_t *
2779
fvm_selector_postfix_create(const char *infix,
2782
const char *group_name[],
2783
const int attribute[])
2785
_tokenized_t te = _tokenize(infix);
2786
fvm_selector_postfix_t * pf = NULL;
2788
if (_n_parser_references == 0)
2789
_parser = _parser_create();
2790
_n_parser_references++;
2792
pf = _parse_tokenized(_parser,
2800
_empty_tokenized(&te);
2802
/* Return postfix expression pointer */
2807
/*----------------------------------------------------------------------------
2808
* Destroy a postfix expression
2811
* pf <-> pointer to postfix structure pointer
2812
*----------------------------------------------------------------------------*/
2815
fvm_selector_postfix_destroy(fvm_selector_postfix_t **postfix)
2817
assert(postfix != NULL);
2818
assert(*postfix != NULL);
2820
_n_parser_references--;
2821
if (_n_parser_references == 0)
2822
_parser_destroy(&_parser);
2824
_postfix_destroy(postfix);
2827
/*----------------------------------------------------------------------------
2828
* Return a pointer to the infix string associated with a postfix expression
2831
* pf <-- pointer to postfix structure
2834
* pointer to original infix string
2835
*----------------------------------------------------------------------------*/
2838
fvm_selector_postfix_get_infix(const fvm_selector_postfix_t *pf)
2845
/*----------------------------------------------------------------------------
2846
* Indicate if a postfix expression depends on coordinates
2849
* pf <-- pointer to postfix structure
2852
* true if expression depends on coordinates, false otherwise
2853
*----------------------------------------------------------------------------*/
2856
fvm_selector_postfix_coords_dep(const fvm_selector_postfix_t *pf)
2860
return pf->coords_dependency;
2863
/*----------------------------------------------------------------------------
2864
* Indicate if a postfix expression depends on normals
2867
* pf <-- pointer to postfix structure
2870
* true if expression depends on normals, false otherwise
2871
*----------------------------------------------------------------------------*/
2874
fvm_selector_postfix_normals_dep(const fvm_selector_postfix_t *pf)
2878
return pf->normals_dependency;
2881
/*----------------------------------------------------------------------------
2882
* Return the number of operands associated with a postfix expression
2883
* missing in the associated group class set
2886
* pf <-- pointer to postfix structure
2889
* number of missing operands
2890
*----------------------------------------------------------------------------*/
2893
fvm_selector_postfix_n_missing(const fvm_selector_postfix_t *pf)
2897
return pf->n_missing_operands;
2900
/*----------------------------------------------------------------------------
2901
* Return a pointer to the name of an of operand associated with a postfix
2902
* expression but missing in the associated group class set
2905
* pf <-- pointer to postfix structure
2906
* id <-- id of missing operand (0 to fvm_selector_postfix_n_missing())
2909
* pointer to name of missing operand
2910
*----------------------------------------------------------------------------*/
2913
fvm_selector_postfix_get_missing(const fvm_selector_postfix_t *pf,
2916
const char *retval = NULL;
2919
if (id > -1 && id < pf->n_missing_operands)
2920
retval = pf->missing_operand[id];
2925
/*----------------------------------------------------------------------------
2926
* Evaluate a postfix expression
2929
* pf <-- pointer to postfix structure
2930
* n_groups <-- number of groups associated with group class
2931
* n_attributes <-- number of attributes associated with group class
2932
* group_id <-- array group ids associated with group class
2933
* attribute_id <-- array of attribute ids associated with group class
2934
* coords <-- coordinates associated with evaluation, or NULL
2935
* normal <-- normal associated with evaluation, or NULL
2938
* true or false base on expression evaluation
2939
*----------------------------------------------------------------------------*/
2942
fvm_selector_postfix_eval(const fvm_selector_postfix_t *pf,
2945
const int group_id[],
2946
const int attribute_id[],
2947
const double coords[],
2948
const double normal[])
2951
_Bool _eval_stack[BASE_STACK_SIZE];
2952
_Bool *eval_stack = _eval_stack;
2953
size_t i = 0, eval_size = 0, eval_max_size = BASE_STACK_SIZE;
2955
/* Evaluate postfix_string */
2959
while (i < pf->size) {
2961
_postfix_type_t type = *((_postfix_type_t *)(pf->elements + i));
2963
i += _postfix_type_size;
2970
int val = *((int *)(pf->elements + i));
2971
i += _postfix_int_size;
2972
eval_stack[eval_size] = false;
2973
for (j = 0; j < n_groups; j++) {
2974
if (val == group_id[j]) {
2975
eval_stack[eval_size] = true;
2982
case PF_ATTRIBUTE_ID:
2985
int val = *((int *)(pf->elements + i));
2986
i += _postfix_int_size;
2987
eval_stack[eval_size] = false;
2988
for (j = 0; j < n_attributes; j++) {
2989
if (val == attribute_id[j]) {
2990
eval_stack[eval_size] = true;
2999
size_t min_eval_size;
3000
_operator_code_t oc = *((_operator_code_t *)(pf->elements + i));
3001
i += _postfix_opcode_size;
3005
else if (oc >= OC_AND && oc <= OC_XOR)
3010
if (eval_size < min_eval_size) {
3011
fvm_selector_postfix_dump(pf, 0, 0, NULL, NULL);
3012
bft_error(__FILE__, __LINE__, 0,
3013
_("Postfix evaluation error."));
3019
if (eval_stack[eval_size-1] == false)
3020
eval_stack[eval_size-1] = true;
3022
eval_stack[eval_size-1] = false;
3025
eval_stack[eval_size-2] = ( eval_stack[eval_size-2]
3026
&& eval_stack[eval_size-1]);
3030
eval_stack[eval_size-2] = ( eval_stack[eval_size-2]
3031
|| eval_stack[eval_size-1]);
3035
if (eval_stack[eval_size-2] != eval_stack[eval_size-1])
3036
eval_stack[eval_size-2] = true;
3038
eval_stack[eval_size-2] = false;
3043
eval_stack[eval_size] = true;
3047
if (n_groups == 0 && n_attributes == 0)
3048
eval_stack[eval_size] = true;
3050
eval_stack[eval_size] = false;
3056
_postfix_type_t type1, type2;
3059
type1 = *((_postfix_type_t *)(pf->elements + i));
3060
i += _postfix_type_size;
3061
val1 = *((int *)(pf->elements + i));
3062
i += _postfix_int_size;
3063
type2 = *((_postfix_type_t *)(pf->elements + i));
3064
i += _postfix_type_size;
3065
val2 = *((int *)(pf->elements + i));
3066
i += _postfix_int_size;
3068
if (type1 == PF_GROUP_ID && type1 == type2) {
3070
eval_stack[eval_size] = false;
3071
for (j = 0; j < n_groups; j++) {
3072
if (group_id[j] >= val1 && group_id[j] <= val2) {
3073
eval_stack[eval_size] = true;
3078
else if (type1 == PF_ATTRIBUTE_ID && type1 == type2) {
3080
eval_stack[eval_size] = false;
3081
for (j = 0; j < n_attributes; j++) {
3082
if (attribute_id[j] >= val1 && attribute_id[j] <= val2) {
3083
eval_stack[eval_size] = true;
3089
fvm_selector_postfix_dump(pf, 0, 0, NULL, NULL);
3090
bft_error(__FILE__, __LINE__, 0,
3092
"range arguments of different or incorrect type."));
3100
eval_stack[eval_size++] = _eval_normal(pf, normal, &i);
3103
eval_stack[eval_size++] = _eval_plane(pf, coords, &i);
3106
eval_stack[eval_size++] = _eval_box(pf, coords, &i);
3109
eval_stack[eval_size++] = _eval_cylinder(pf, coords, &i);
3112
eval_stack[eval_size++] = _eval_sphere(pf, coords, &i);
3116
eval_stack[eval_size++] = _eval_coord_gt(pf, coords, &i);
3119
eval_stack[eval_size++] = _eval_coord_lt(pf, coords, &i);
3122
eval_stack[eval_size++] = _eval_coord_ge(pf, coords, &i);
3125
eval_stack[eval_size++] = _eval_coord_le(pf, coords, &i);
3129
bft_error(__FILE__, __LINE__, 0,
3130
_("Operator %s not currently implemented."),
3131
_operator_name[oc]);
3133
} /* End of inside (operator) switch */
3139
fvm_selector_postfix_dump(pf, 0, 0, NULL, NULL);
3140
bft_error(__FILE__, __LINE__, 0,
3141
_("Postfix evaluation error."));
3144
if (eval_size == eval_max_size) {
3146
if (eval_stack == _eval_stack)
3147
BFT_MALLOC(eval_stack, eval_max_size, _Bool);
3149
BFT_REALLOC(eval_stack, eval_max_size, _Bool);
3152
} /* End of loop on postfix elements */
3154
if (eval_size != 1) {
3155
fvm_selector_postfix_dump(pf, 0, 0, NULL, NULL);
3156
bft_error(__FILE__, __LINE__, 0,
3157
_("Postfix evaluation error."));
3160
retval = eval_stack[0];
3162
if (eval_stack != _eval_stack)
3163
BFT_FREE(eval_stack);
3168
/*----------------------------------------------------------------------------
3169
* Dump the contents of a postfix structure in human readable form
3172
* pf <-> pointer to postfix structure
3173
* n_groups <-- number of groups
3174
* n_attributes <-- number of attributes
3175
* group_name <-- array group names (sorted)
3176
* attribute <-- array of attribute numbers (sorted)
3177
*----------------------------------------------------------------------------*/
3180
fvm_selector_postfix_dump(const fvm_selector_postfix_t *pf,
3183
const char *group_name[],
3184
const int attribute[])
3189
"Postfix expression dump:\n"
3190
" Coordinates dependency: %d\n"
3191
" Normals dependency: %d\n"
3195
(int)pf->coords_dependency,
3196
(int)pf->normals_dependency,
3199
/* Dump postfix_string */
3203
while (i < pf->size) {
3205
_postfix_type_t type = *((_postfix_type_t *)(pf->elements + i));
3207
i += _postfix_type_size;
3212
_operator_code_t oc = *((_operator_code_t *)(pf->elements + i));
3213
bft_printf(" %s\n", _operator_name[oc]);
3214
i += _postfix_opcode_size;
3218
case PF_ATTRIBUTE_ID:
3221
int val = *((int *)(pf->elements + i));
3222
if (type == PF_GROUP_ID) {
3224
bft_printf(" %d (non-existing group id)\n", val);
3225
else if (n_groups > 0)
3226
bft_printf(" %d (group: \"%s\")\n", val, group_name[val]);
3228
bft_printf(" %d (group id)\n");
3230
else if (type == PF_ATTRIBUTE_ID) {
3232
bft_printf(" %d (non-existing attribute id)\n", val);
3233
else if (n_attributes > 0)
3234
bft_printf(" %d (attribute: %d)\n", val, attribute[val]);
3236
bft_printf(" %d (attribute id)\n");
3239
bft_printf(" %d\n", val);
3240
i += _postfix_int_size;
3245
double val = *((double *)(pf->elements + i));
3246
bft_printf(" %g\n", val);
3247
i += _postfix_float_size;
3257
if (pf->n_missing_operands > 0) {
3258
bft_printf(" Missing operands: %d\n",
3259
pf->n_missing_operands);
3260
for (i = 0; i < (size_t)(pf->n_missing_operands); i++)
3261
bft_printf(" %s\n", pf->missing_operand[i]);
3267
/*----------------------------------------------------------------------------*/
3271
#endif /* __cplusplus */