~ubuntu-branches/ubuntu/precise/code-saturne/precise

« back to all changes in this revision

Viewing changes to src/fvm/fvm_selector_postfix.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2011-11-24 00:00:08 UTC
  • mfrom: (6.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20111124000008-2vo99e38267942q5
Tags: 2.1.0-3
Install a missing file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*============================================================================
 
2
 * Expression handling for entity selection based on groups or attributes
 
3
 *============================================================================*/
 
4
 
 
5
/*----------------------------------------------------------------------------*/
 
6
 
 
7
/*
 
8
  This file is part of Code_Saturne, a general-purpose CFD tool.
 
9
 
 
10
  Copyright (C) 1998-2011 EDF S.A.
 
11
 
 
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
 
15
  version.
 
16
 
 
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
 
20
  details.
 
21
 
 
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.
 
25
*/
 
26
 
 
27
/*----------------------------------------------------------------------------*/
 
28
 
 
29
#if defined(HAVE_CONFIG_H)
 
30
#include "cs_config.h"
 
31
#endif
 
32
 
 
33
/*----------------------------------------------------------------------------
 
34
 * Standard C library headers
 
35
 *----------------------------------------------------------------------------*/
 
36
 
 
37
#include <stdio.h>
 
38
#include <stdlib.h>
 
39
#include <string.h>
 
40
#include <assert.h>
 
41
#include <math.h>
 
42
 
 
43
/*----------------------------------------------------------------------------
 
44
 * BFT library headers
 
45
 *----------------------------------------------------------------------------*/
 
46
 
 
47
#include <bft_mem.h>
 
48
#include <bft_error.h>
 
49
#include <bft_printf.h>
 
50
 
 
51
/*----------------------------------------------------------------------------
 
52
 *  Local headers
 
53
 *----------------------------------------------------------------------------*/
 
54
 
 
55
#include "fvm_defs.h"
 
56
#include "fvm_config_defs.h"
 
57
 
 
58
/*----------------------------------------------------------------------------
 
59
 *  Header for the current file
 
60
 *----------------------------------------------------------------------------*/
 
61
 
 
62
#include "fvm_selector_postfix.h"
 
63
 
 
64
/*----------------------------------------------------------------------------*/
 
65
 
 
66
#ifdef __cplusplus
 
67
extern "C" {
 
68
#if 0
 
69
} /* Fake brace to force Emacs auto-indentation back to column 0 */
 
70
#endif
 
71
#endif /* __cplusplus */
 
72
 
 
73
/*=============================================================================
 
74
 * Macro definitions
 
75
 *============================================================================*/
 
76
 
 
77
/*
 
78
 * Allowed operand types (bit mask)
 
79
 */
 
80
 
 
81
#define _OPERAND_INT          (1 << 0)
 
82
#define _OPERAND_DOUBLE       (1 << 1)
 
83
#define _OPERAND_STRING       (1 << 2)
 
84
#define _OPERAND_GEOMETRIC    (1 << 3)
 
85
 
 
86
/* Base stack length */
 
87
 
 
88
#define BASE_STACK_SIZE 32
 
89
 
 
90
/* Geometric operation macros*/
 
91
 
 
92
#define _DOT_PRODUCT(v1, v2) \
 
93
  (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2])
 
94
 
 
95
#define _MODULE(v) \
 
96
  sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])
 
97
 
 
98
/*============================================================================
 
99
 * Local type definitions
 
100
 *============================================================================*/
 
101
 
 
102
/*----------------------------------------------------------------------------
 
103
 * Types of arguments or oprands for an operator
 
104
 *----------------------------------------------------------------------------*/
 
105
 
 
106
typedef enum {
 
107
 
 
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 */
 
117
 
 
118
} _operator_type_t;
 
119
 
 
120
/*----------------------------------------------------------------------------
 
121
 * List of operator codes and names
 
122
 *----------------------------------------------------------------------------*/
 
123
 
 
124
typedef enum {
 
125
 
 
126
  OC_L_PAREN,
 
127
  OC_R_PAREN,
 
128
 
 
129
  OC_NOT,
 
130
  OC_AND,
 
131
  OC_OR,
 
132
  OC_XOR,
 
133
 
 
134
  OC_ALL,
 
135
  OC_NO_GROUP,
 
136
  OC_RANGE,
 
137
 
 
138
  OC_NORMAL,
 
139
  OC_PLANE,
 
140
  OC_BOX,
 
141
  OC_CYLINDER,
 
142
  OC_SPHERE,
 
143
 
 
144
  OC_GT,
 
145
  OC_LT,
 
146
  OC_GE,
 
147
  OC_LE,
 
148
 
 
149
  OC_NONE
 
150
 
 
151
} _operator_code_t;
 
152
 
 
153
static const char *_operator_name[] = {"(", ")",
 
154
                                       "not", "and", "or", "xor",
 
155
                                       "all", "no_group", "range",
 
156
                                       "normal", "plane", "box",
 
157
                                       "cylinder", "sphere",
 
158
                                       ">", "<", ">=", "<=",
 
159
                                       "not_an_operator"};
 
160
 
 
161
/*----------------------------------------------------------------------------
 
162
 * Types of postfix elements
 
163
 *----------------------------------------------------------------------------*/
 
164
 
 
165
typedef enum {
 
166
 
 
167
  PF_OPCODE,
 
168
  PF_GROUP_ID,
 
169
  PF_ATTRIBUTE_ID,
 
170
  PF_INT,
 
171
  PF_FLOAT
 
172
 
 
173
} _postfix_type_t;
 
174
 
 
175
/*----------------------------------------------------------------------------
 
176
 * Definition of a tokenized expression
 
177
 *----------------------------------------------------------------------------*/
 
178
 
 
179
typedef struct {
 
180
 
 
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) */
 
187
 
 
188
  int     size;                   /* Current string size */
 
189
  int     max_size;               /* Maximum string size */
 
190
 
 
191
  char   *tokens;                 /* Tokens array */
 
192
 
 
193
} _tokenized_t;
 
194
 
 
195
/*----------------------------------------------------------------------------
 
196
 * Operator definition
 
197
 *----------------------------------------------------------------------------*/
 
198
 
 
199
typedef struct {
 
200
 
 
201
  _operator_code_t   code;        /* Operator code number */
 
202
  _operator_type_t   type;        /* Operator type */
 
203
 
 
204
  int                priority;    /* Priority */
 
205
 
 
206
  char               name[16];    /* Operator name string */
 
207
 
 
208
} _operator_t;
 
209
 
 
210
/*----------------------------------------------------------------------------
 
211
 * Parser object
 
212
 *----------------------------------------------------------------------------*/
 
213
 
 
214
typedef struct {
 
215
 
 
216
  int           n_operators;       /* Number of possible operators */
 
217
  _operator_t  *operators;         /* Array of allowed operators */
 
218
 
 
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 */
 
222
 
 
223
  size_t        keywords_size;     /* Size of keyword buffer */
 
224
  char         *keywords;          /* Pointer to keyword buffer */
 
225
 
 
226
} _parser_t;
 
227
 
 
228
/*----------------------------------------------------------------------------
 
229
 * Stack of parsed operator elements
 
230
 *----------------------------------------------------------------------------*/
 
231
 
 
232
typedef struct {
 
233
 
 
234
  const _operator_t  *op;        /* Pointer to operator definition */
 
235
  int                 token_id;  /* Associated token's id */
 
236
 
 
237
} _stack_entry_t;
 
238
 
 
239
typedef struct {
 
240
 
 
241
  size_t  size;                                /* Current memory size */
 
242
  size_t  max_size;                            /* Maximum memory size */
 
243
 
 
244
  _stack_entry_t  _elements[BASE_STACK_SIZE];  /* Base working stack */
 
245
  _stack_entry_t  *elements;                   /* Pointer to _elements
 
246
                                                  or allocated */
 
247
 
 
248
} _stack_t;
 
249
 
 
250
/*============================================================================
 
251
 * Type definitions
 
252
 *============================================================================*/
 
253
 
 
254
/*----------------------------------------------------------------------------
 
255
 * Postfix expression object
 
256
 *----------------------------------------------------------------------------*/
 
257
 
 
258
struct _fvm_selector_postfix_t {
 
259
 
 
260
  _Bool   coords_dependency;      /* Does evaluation require coordinates ? */
 
261
  _Bool   normals_dependency;     /* Does evaluation require normals ? */
 
262
 
 
263
  size_t  size;                   /* Current memory size */
 
264
  size_t  max_size;               /* Maximum memory size */
 
265
 
 
266
  char   *infix;                  /* Copy of original infix expression */
 
267
  unsigned char  *elements;       /* Contents array */
 
268
 
 
269
  int     n_missing_operands;     /* Number of operands corresponding to
 
270
                                     missing group names */
 
271
  char **missing_operand;         /* Array of missing group names */
 
272
 
 
273
};
 
274
 
 
275
/*============================================================================
 
276
 * Global variables
 
277
 *============================================================================*/
 
278
 
 
279
/* Reference count and pointer to global parser object */
 
280
 
 
281
static int _n_parser_references = 0;
 
282
static _parser_t *_parser = NULL;
 
283
 
 
284
/* Compute sizes so as to have aligned data */
 
285
 
 
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));
 
298
 
 
299
/*============================================================================
 
300
 * Private function definitions
 
301
 *============================================================================*/
 
302
 
 
303
/*----------------------------------------------------------------------------
 
304
 * Add an operator definition to a parser.
 
305
 *
 
306
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
315
 
 
316
static void
 
317
_add_operator(_parser_t          *this_parser,
 
318
              const char         *name,
 
319
              _operator_code_t    operator_code,
 
320
              _operator_type_t    operator_type,
 
321
              int                 priority,
 
322
              int                 n_keywords,
 
323
              const char        **keywords)
 
324
{
 
325
  int i;
 
326
 
 
327
  /* Initial checks */
 
328
 
 
329
  assert(this_parser != NULL);
 
330
  assert(n_keywords > 0);
 
331
 
 
332
  /* Resize structures */
 
333
 
 
334
  BFT_REALLOC(this_parser->operators,
 
335
              this_parser->n_operators + 1,
 
336
              _operator_t);
 
337
 
 
338
  if (n_keywords > 0) {
 
339
 
 
340
    size_t keywords_size = 0;
 
341
 
 
342
    for (i = 0; i < n_keywords; i++)
 
343
      keywords_size += (strlen(keywords[i]) + 1);
 
344
 
 
345
    BFT_REALLOC(this_parser->keyword_op_id,
 
346
                this_parser->n_keywords + n_keywords,
 
347
                int);
 
348
 
 
349
    BFT_REALLOC(this_parser->keyword,
 
350
                this_parser->n_keywords + n_keywords,
 
351
                char *);
 
352
 
 
353
    BFT_REALLOC(this_parser->keywords,
 
354
                this_parser->keywords_size + keywords_size,
 
355
                char);
 
356
 
 
357
  }
 
358
 
 
359
  /* Fill structures */
 
360
 
 
361
  i = this_parser->n_operators;
 
362
 
 
363
  this_parser->operators[i].code = operator_code;
 
364
  this_parser->operators[i].priority = priority;
 
365
  this_parser->operators[i].type = operator_type;
 
366
 
 
367
  strncpy(this_parser->operators[i].name, name, 15);
 
368
  this_parser->operators[i].name[15] = '\0';
 
369
 
 
370
  for (i = 0; i < n_keywords; i++) {
 
371
 
 
372
    size_t  l = strlen(keywords[i]) + 1;
 
373
 
 
374
    this_parser->keyword_op_id[this_parser->n_keywords]
 
375
      = this_parser->n_operators;
 
376
 
 
377
    memcpy(this_parser->keywords + this_parser->keywords_size,
 
378
           keywords[i],
 
379
           l);
 
380
 
 
381
    this_parser->n_keywords += 1;
 
382
    this_parser->keywords_size += l;
 
383
 
 
384
  }
 
385
 
 
386
  this_parser->n_operators += 1;
 
387
}
 
388
 
 
389
/*----------------------------------------------------------------------------
 
390
 * Creation of a parser object.
 
391
 *
 
392
 * parameters:
 
393
 *
 
394
 * returns:
 
395
 *   pointer to new parser
 
396
 *----------------------------------------------------------------------------*/
 
397
 
 
398
static _parser_t *
 
399
_parser_create(void)
 
400
{
 
401
  int i;
 
402
 
 
403
  const char *kw_l_paren[] = {"("};
 
404
  const char *kw_r_paren[] = {")"};
 
405
 
 
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"};
 
413
 
 
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"};
 
419
 
 
420
  const char *kw_gt[] = {">"};
 
421
  const char *kw_lt[] = {"<"};
 
422
  const char *kw_ge[] = {">="};
 
423
  const char *kw_le[] = {"<="};
 
424
 
 
425
  _parser_t *p = NULL;
 
426
 
 
427
  /* Create base structure */
 
428
 
 
429
  BFT_MALLOC(p, 1, _parser_t);
 
430
 
 
431
  p->n_operators = 0;
 
432
  p->operators = NULL;
 
433
 
 
434
  p->n_keywords = 0;
 
435
  p->keyword_op_id = NULL;
 
436
  p->keyword = NULL;
 
437
 
 
438
  p->keywords_size = 0;
 
439
  p->keywords = NULL;
 
440
 
 
441
  /* Add operator definitions */
 
442
 
 
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);
 
445
 
 
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);
 
450
 
 
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);
 
454
 
 
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);
 
460
 
 
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);
 
465
 
 
466
  /* Build keyword pointers */
 
467
 
 
468
  p->keyword[0] = p->keywords;
 
469
 
 
470
  for (i = 1; i < p->n_keywords; i++)
 
471
    p->keyword[i]
 
472
      = p->keyword[i-1] + strlen(p->keyword[i-1]) + 1;
 
473
 
 
474
  /* Return parser object */
 
475
 
 
476
  return p;
 
477
}
 
478
 
 
479
/*----------------------------------------------------------------------------
 
480
 * Destruction of a parser.
 
481
 *
 
482
 * parameters:
 
483
 *   this_parser <-> parser to destroy
 
484
 *----------------------------------------------------------------------------*/
 
485
 
 
486
static void
 
487
_parser_destroy(_parser_t  **this_parser)
 
488
{
 
489
  if (*this_parser != NULL) {
 
490
 
 
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);
 
495
 
 
496
    BFT_FREE(*this_parser);
 
497
 
 
498
  }
 
499
}
 
500
 
 
501
/*----------------------------------------------------------------------------
 
502
 * Print content of a parser object.
 
503
 *
 
504
 * parameters:
 
505
 *   this_parser <-- parser object
 
506
 *----------------------------------------------------------------------------*/
 
507
 
 
508
static void
 
509
_parser_dump(const _parser_t  *this_parser)
 
510
{
 
511
  int i;
 
512
 
 
513
  const char *type_name[] = {"(", ")", "unary", "binary", "function",
 
514
                             "coord condition", "definition", "math_func"};
 
515
 
 
516
  if (this_parser == NULL)
 
517
    return;
 
518
 
 
519
  /* Global indicators */
 
520
  /*-------------------*/
 
521
 
 
522
  bft_printf("\n"
 
523
             "Parser:\n\n"
 
524
             "Number of operators:  %d\n"
 
525
             "Number of keywords:   %d\n\n",
 
526
             this_parser->n_operators,
 
527
             this_parser->n_keywords);
 
528
 
 
529
 
 
530
  /* Operators and related part of keywords array */
 
531
 
 
532
  if (this_parser->n_operators > 0)
 
533
    bft_printf("Operators:\n"
 
534
               "    id  | name     | code | pri | type  \n"
 
535
               "    ------------------------------------\n");
 
536
 
 
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]);
 
541
  }
 
542
 
 
543
  if (this_parser->n_keywords > 0)
 
544
    bft_printf("\n"
 
545
               "Keywords:\n"
 
546
               "    id  | op_id | name\n"
 
547
               "    ------------------\n");
 
548
 
 
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]);
 
552
 
 
553
  bft_printf("\n");
 
554
}
 
555
 
 
556
/*----------------------------------------------------------------------------
 
557
 * Tokenize an infix expression string.
 
558
 *
 
559
 * parameters:
 
560
 *   infix    <-- string parsed
 
561
 *
 
562
 * returns:
 
563
 *   a tokenized_t structure corresponding to the infix string
 
564
 *----------------------------------------------------------------------------*/
 
565
 
 
566
static _tokenized_t
 
567
_tokenize(const char  *infix)
 
568
{
 
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 */
 
572
 
 
573
  _tokenized_t te;
 
574
 
 
575
  /* Initialization */
 
576
 
 
577
  te.n_tokens = 0;
 
578
  te.infix_id = NULL;
 
579
  te.token_id = NULL;
 
580
  te.protected = NULL;
 
581
 
 
582
  te.size = 0;
 
583
  te.max_size = 0;
 
584
  te.tokens = NULL;
 
585
 
 
586
  if (infix == NULL)
 
587
    return te;
 
588
 
 
589
  /* Allocate tokenization structure */
 
590
 
 
591
  l = strlen(infix);
 
592
 
 
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 */
 
596
 
 
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);
 
601
 
 
602
  for (i = 0; i < l; i++)
 
603
    te.protected[i] = false;
 
604
 
 
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) */
 
608
 
 
609
  protected = 0;
 
610
  tok_len = 0;
 
611
 
 
612
  while (i < l) {
 
613
 
 
614
    char c = infix[i];
 
615
 
 
616
    /* Regular case, where previous character was not protected */
 
617
 
 
618
    if (protected == 0) {
 
619
 
 
620
      /* Protection character */
 
621
 
 
622
      if (c == '\\') {
 
623
        protected = 1;
 
624
        te.protected[te.n_tokens] = true;
 
625
      }
 
626
 
 
627
      /* Fully protected string */
 
628
 
 
629
      else if (c == '"' || c == '\'') {
 
630
        protected = 2;
 
631
        start_quote_id = i;
 
632
        te.protected[te.n_tokens] = true;
 
633
      }
 
634
 
 
635
      /* Whitespace */
 
636
 
 
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';
 
641
          te.n_tokens += 1;
 
642
          te.size += tok_len+1;
 
643
          tok_len = 0;
 
644
        }
 
645
      }
 
646
 
 
647
      /* Other punctuation characters */
 
648
 
 
649
      else if (   c == '(' || c == ')'
 
650
               || c == '[' || c == ']'
 
651
               || c == ',' || c == ';'
 
652
               || c == '!' || c == '^' || c == '|' || c == '&'
 
653
               || c == '=' || c == '<' || c == '>') {
 
654
 
 
655
        char c2 = '\0';
 
656
 
 
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';
 
660
          te.n_tokens += 1;
 
661
          te.size += tok_len+1;
 
662
          tok_len = 0;
 
663
        }
 
664
 
 
665
        /* Add token, handling possible 2-character punctuation */
 
666
 
 
667
        te.token_id[te.n_tokens] = te.size;
 
668
        te.tokens[te.size] = c;
 
669
 
 
670
        if (i+1 < l)
 
671
          c2 = infix[i+1];
 
672
 
 
673
        if (   ((c == '=' || c == '<' || c == '>') && c2 == '=')
 
674
            || (c == '!' && c2 == '=')
 
675
            || (c == '|' && c2 == '|')
 
676
            || (c == '&' && c2 == '&')) {
 
677
          i += 1;
 
678
          te.tokens[te.size + 1] = '=';
 
679
          te.tokens[te.size + 2] = '\0';
 
680
          te.size += 3;
 
681
        }
 
682
        else {
 
683
          te.tokens[te.size + 1] = '\0';
 
684
          te.size += 2;
 
685
        }
 
686
        te.infix_id[te.n_tokens] = i;
 
687
        te.n_tokens += 1;
 
688
 
 
689
      }
 
690
 
 
691
      /* Regular characters (token) */
 
692
 
 
693
      else {
 
694
        te.tokens[te.size + tok_len] = infix[i];
 
695
        if (tok_len == 0)
 
696
          te.infix_id[te.n_tokens] = i;
 
697
        tok_len++;
 
698
      }
 
699
 
 
700
    }
 
701
 
 
702
    /* Cases where previous character was protected */
 
703
 
 
704
    else if (protected == 1) {
 
705
 
 
706
      protected = 0;
 
707
      te.tokens[te.size + tok_len] = infix[i];
 
708
      if (tok_len == 0)
 
709
        te.infix_id[te.n_tokens] = i;
 
710
      tok_len++;
 
711
 
 
712
    }
 
713
 
 
714
    else if (protected == 2) {
 
715
 
 
716
      /* Single protection character */
 
717
 
 
718
      if (c == '\\')
 
719
        protected = 3;
 
720
 
 
721
      /* End of string protection */
 
722
 
 
723
      else if (c == infix[start_quote_id]) {
 
724
        protected = 0;
 
725
        start_quote_id = l;
 
726
      }
 
727
 
 
728
      else {
 
729
        te.tokens[te.size + tok_len] = infix[i];
 
730
        if (tok_len == 0)
 
731
          te.infix_id[te.n_tokens] = i;
 
732
        tok_len++;
 
733
      }
 
734
 
 
735
    }
 
736
 
 
737
    else { /* if (protected == 3) */
 
738
 
 
739
      te.tokens[te.size + tok_len] = infix[i];
 
740
      if (tok_len == 0)
 
741
        te.infix_id[te.n_tokens] = i;
 
742
      tok_len++;
 
743
      protected = 2;
 
744
 
 
745
    }
 
746
 
 
747
    i+= 1;
 
748
 
 
749
  } /* End of loop in infix string characters */
 
750
 
 
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';
 
754
    te.n_tokens += 1;
 
755
    te.size += tok_len+1;
 
756
    tok_len = 0;
 
757
  }
 
758
 
 
759
  if (protected == 1)
 
760
    bft_error(__FILE__, __LINE__, 0,
 
761
              _("Error tokenizing expression:\n"
 
762
                "%s\n"
 
763
                "Missing character after \\\n"),
 
764
              infix);
 
765
  else if (protected >= 2)
 
766
    bft_error(__FILE__, __LINE__, 0,
 
767
              _("Error tokenizing expression:\n"
 
768
                "%s\n"
 
769
                "Missing closing quote for subexpression:\n"
 
770
                "%s\n"),
 
771
              infix, infix + start_quote_id);
 
772
 
 
773
  /* Resize to adjusted size */
 
774
 
 
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);
 
779
 
 
780
  /* Return tokenization structure */
 
781
 
 
782
  return te;
 
783
}
 
784
 
 
785
/*----------------------------------------------------------------------------
 
786
 * Empty a tokenized expression string.
 
787
 *
 
788
 * parameters:
 
789
 *   te    <-> tokenized expression
 
790
 *----------------------------------------------------------------------------*/
 
791
 
 
792
static void
 
793
_empty_tokenized(_tokenized_t  *te)
 
794
{
 
795
  te->n_tokens = 0;
 
796
  te->size = 0;
 
797
  te->max_size = 0;
 
798
  BFT_FREE(te->infix_id);
 
799
  BFT_FREE(te->token_id);
 
800
  BFT_FREE(te->protected);
 
801
  BFT_FREE(te->tokens);
 
802
}
 
803
 
 
804
/*----------------------------------------------------------------------------
 
805
 * Dump a tokenized expression string.
 
806
 *
 
807
 * parameters:
 
808
 *   infix <-- string parsed
 
809
 *   te    <-- tokenized expression
 
810
 *----------------------------------------------------------------------------*/
 
811
 
 
812
static void
 
813
_dump_tokenized(const char          *infix,
 
814
                const _tokenized_t   te)
 
815
{
 
816
  int i;
 
817
 
 
818
  bft_printf("\n"
 
819
             "Tokenization:\n\n"
 
820
             "Infix:\n%s\n"
 
821
             "Tokens: %d\n",
 
822
             infix, te.n_tokens);
 
823
 
 
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");
 
829
    else
 
830
      bft_printf(")\n");
 
831
  }
 
832
}
 
833
 
 
834
/*----------------------------------------------------------------------------
 
835
 * Initialize a stack
 
836
 *
 
837
 * parameters:
 
838
 *   stack <-> stack
 
839
 *----------------------------------------------------------------------------*/
 
840
 
 
841
static void
 
842
_stack_initialize(_stack_t *stack)
 
843
{
 
844
  stack->size = 0;
 
845
  stack->max_size = BASE_STACK_SIZE;
 
846
  stack->elements = stack->_elements;
 
847
}
 
848
 
 
849
/*----------------------------------------------------------------------------
 
850
 * Empty a stack
 
851
 *
 
852
 * parameters:
 
853
 *   stack <-> stack
 
854
 *----------------------------------------------------------------------------*/
 
855
 
 
856
static void
 
857
_stack_empty(_stack_t *stack)
 
858
{
 
859
  stack->size = 0;
 
860
  stack->max_size = BASE_STACK_SIZE;
 
861
  if (stack->elements != stack->_elements) {
 
862
    BFT_FREE(stack->elements);
 
863
    stack->elements = stack->_elements;
 
864
  }
 
865
}
 
866
 
 
867
/*----------------------------------------------------------------------------
 
868
 * Push operator info to the top of the stack
 
869
 *
 
870
 * parameters:
 
871
 *   stack    <-> stack
 
872
 *   op       <-- Pointer to operator definition
 
873
 *   token_id <-- associated token id
 
874
 *----------------------------------------------------------------------------*/
 
875
 
 
876
 
 
877
inline static void
 
878
_stack_push(_stack_t           *stack,
 
879
            const _operator_t  *op,
 
880
            int                 token_id)
 
881
{
 
882
  _stack_entry_t  *e;
 
883
 
 
884
  assert(stack != NULL);
 
885
 
 
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));
 
892
      }
 
893
      else
 
894
        BFT_REALLOC(stack->elements, stack->max_size, _stack_entry_t);
 
895
    }
 
896
  }
 
897
 
 
898
  e = stack->elements + stack->size;
 
899
 
 
900
  e->op = op;
 
901
  e->token_id = token_id;
 
902
 
 
903
  stack->size++;
 
904
}
 
905
 
 
906
/*----------------------------------------------------------------------------
 
907
 * Pop an entry from the top of the stack
 
908
 *
 
909
 * parameters:
 
910
 *   stack <-> stack
 
911
 *   id    --> optional id associated with value, or NULL
 
912
 *
 
913
 * returns:
 
914
 *   the value on the top of the stack
 
915
 *----------------------------------------------------------------------------*/
 
916
 
 
917
inline static _stack_entry_t
 
918
_stack_pop(_stack_t  *stack)
 
919
{
 
920
  assert(stack != NULL);
 
921
 
 
922
  if (stack->size == 0)
 
923
    bft_error(__FILE__, __LINE__, 0,
 
924
              _("Trying to pop an entry from empty stack."));
 
925
 
 
926
  return stack->elements[--(stack->size)];
 
927
}
 
928
 
 
929
/*----------------------------------------------------------------------------
 
930
 * Return the number of elements in a stack
 
931
 *
 
932
 * parameters:
 
933
 *   stack <-- stack
 
934
 *
 
935
 * returns:
 
936
 *   number of elements in the stack
 
937
 *----------------------------------------------------------------------------*/
 
938
 
 
939
inline static size_t
 
940
_stack_size(_stack_t  *stack)
 
941
{
 
942
  return stack->size;
 
943
}
 
944
 
 
945
/*----------------------------------------------------------------------------
 
946
 * Return pointer to operator definition for the entry at the top of
 
947
 * a stack (without modifying the stack)
 
948
 *
 
949
 * parameters:
 
950
 *   stack <-> stack
 
951
 *
 
952
 * returns:
 
953
 *   the value on the top of the stack
 
954
 *----------------------------------------------------------------------------*/
 
955
 
 
956
inline static const _operator_t *
 
957
_stack_top(const _stack_t  *stack)
 
958
{
 
959
  assert(stack != NULL);
 
960
 
 
961
  if (stack->size == 0)
 
962
    bft_error(__FILE__, __LINE__, 0,
 
963
              _("Querying a top value from empty stack."));
 
964
 
 
965
  return (stack->elements + stack->size - 1)->op;
 
966
}
 
967
 
 
968
/*----------------------------------------------------------------------------
 
969
 * Initialize a postfix expression
 
970
 *
 
971
 * parameters:
 
972
 *   infix <-> initially infix expression
 
973
 *
 
974
 * returns:
 
975
 *   new postfix structure
 
976
 *----------------------------------------------------------------------------*/
 
977
 
 
978
static fvm_selector_postfix_t *
 
979
_postfix_create(const char *infix)
 
980
{
 
981
  size_t i;
 
982
  size_t size = strlen(infix);
 
983
  fvm_selector_postfix_t *pf = NULL;
 
984
 
 
985
  BFT_MALLOC(pf, 1, fvm_selector_postfix_t);
 
986
 
 
987
  pf->coords_dependency = false;
 
988
  pf->normals_dependency = false;
 
989
 
 
990
  pf->size = 0;
 
991
  pf->max_size = size * sizeof(size_t);
 
992
 
 
993
  BFT_MALLOC(pf->infix, size + 1, char);
 
994
  strcpy(pf->infix, infix);
 
995
 
 
996
  BFT_MALLOC(pf->elements, pf->max_size, unsigned char);
 
997
  for (i = 0; i < pf->max_size; pf->elements[i++] = '\0');
 
998
 
 
999
  pf->n_missing_operands = 0;
 
1000
  pf->missing_operand = NULL;
 
1001
 
 
1002
  return pf;
 
1003
}
 
1004
 
 
1005
/*----------------------------------------------------------------------------
 
1006
 * Destroy a postfix expression
 
1007
 *
 
1008
 * parameters:
 
1009
 *   pf <-> pointer to structure pointer that should be destroyed
 
1010
 *----------------------------------------------------------------------------*/
 
1011
 
 
1012
static void
 
1013
_postfix_destroy(fvm_selector_postfix_t **pf)
 
1014
{
 
1015
  fvm_selector_postfix_t *_pf = *pf;
 
1016
 
 
1017
  if (*pf != NULL) {
 
1018
 
 
1019
    BFT_FREE(_pf->infix);
 
1020
    BFT_FREE(_pf->elements);
 
1021
 
 
1022
    if (_pf->n_missing_operands > 0) {
 
1023
      int i;
 
1024
      for (i = 0; i < _pf->n_missing_operands; i++)
 
1025
        BFT_FREE(_pf->missing_operand[i]);
 
1026
      BFT_FREE(_pf->missing_operand);
 
1027
    }
 
1028
 
 
1029
    BFT_FREE(_pf);
 
1030
    *pf = _pf;
 
1031
  }
 
1032
}
 
1033
 
 
1034
/*----------------------------------------------------------------------------
 
1035
 * Grow postfix string for future additions
 
1036
 *
 
1037
 * parameters:
 
1038
 *   pf     <-> posfix string
 
1039
 *   size_t <-- new_size
 
1040
 *----------------------------------------------------------------------------*/
 
1041
 
 
1042
static void
 
1043
_postfix_grow(fvm_selector_postfix_t  *pf,
 
1044
              size_t                   new_size)
 
1045
{
 
1046
  size_t i;
 
1047
  size_t old_max_size = pf->max_size;
 
1048
  if (old_max_size*2 > new_size)
 
1049
    pf->max_size *= 2;
 
1050
  else
 
1051
    pf->max_size = new_size;
 
1052
 
 
1053
  BFT_REALLOC(pf->elements, pf->max_size, unsigned char);
 
1054
  for (i = old_max_size; i < pf->max_size; pf->elements[i++] = '\0');
 
1055
}
 
1056
 
 
1057
/*----------------------------------------------------------------------------
 
1058
 * Adjust max size of postfix structure to current size
 
1059
 *
 
1060
 * parameters:
 
1061
 *   pf     <-> posfix string
 
1062
 *----------------------------------------------------------------------------*/
 
1063
 
 
1064
static void
 
1065
_postfix_adjust(fvm_selector_postfix_t  *pf)
 
1066
{
 
1067
  if (pf->size != pf->max_size) {
 
1068
    pf->max_size = pf->size;
 
1069
    BFT_REALLOC(pf->elements, pf->max_size, unsigned char);
 
1070
  }
 
1071
}
 
1072
 
 
1073
/*----------------------------------------------------------------------------
 
1074
 * Add an operator code to a postfix expression
 
1075
 *
 
1076
 * parameters:
 
1077
 *   pf   <-> pointer to postfix structure
 
1078
 *   code <-- operator code
 
1079
 *----------------------------------------------------------------------------*/
 
1080
 
 
1081
static void
 
1082
_postfix_add_opcode(fvm_selector_postfix_t  *pf,
 
1083
                    _operator_code_t         code)
 
1084
{
 
1085
  size_t add_size = _postfix_type_size + _postfix_opcode_size;
 
1086
 
 
1087
  /* Update postfix */
 
1088
 
 
1089
  if (pf->size + add_size > pf->max_size)
 
1090
    _postfix_grow(pf, pf->size + add_size);
 
1091
 
 
1092
  *((_postfix_type_t *)(pf->elements + pf->size)) = PF_OPCODE;
 
1093
  *((_operator_code_t *)(pf->elements + pf->size + _postfix_type_size))
 
1094
    = code;
 
1095
 
 
1096
  pf->size += add_size;
 
1097
}
 
1098
 
 
1099
/*----------------------------------------------------------------------------
 
1100
 * Add an integer to a postfix expression
 
1101
 *
 
1102
 * parameters:
 
1103
 *   pf   <-> pointer to postfix structure
 
1104
 *   val  <-- integer value
 
1105
 *   type <-- integer subtype (PF_GROUP_ID, PF_ATTRIBUTE_ID, or PF_INT)
 
1106
 *----------------------------------------------------------------------------*/
 
1107
 
 
1108
static void
 
1109
_postfix_add_int(fvm_selector_postfix_t  *pf,
 
1110
                 int                      val,
 
1111
                 _postfix_type_t          type)
 
1112
{
 
1113
  size_t add_size = _postfix_type_size + _postfix_int_size;
 
1114
 
 
1115
  /* Update postfix */
 
1116
 
 
1117
  if (pf->size + add_size > pf->max_size)
 
1118
    _postfix_grow(pf, pf->size + add_size);
 
1119
 
 
1120
  *((_postfix_type_t *)(pf->elements + pf->size)) = type;
 
1121
  *((int *)(pf->elements + pf->size + _postfix_type_size)) = val;
 
1122
 
 
1123
  pf->size += add_size;
 
1124
}
 
1125
 
 
1126
/*----------------------------------------------------------------------------
 
1127
 * Add an float to a postfix expression
 
1128
 *
 
1129
 * parameters:
 
1130
 *   pf  <-> pointer to postfix structure
 
1131
 *   val <-- integer value
 
1132
 *----------------------------------------------------------------------------*/
 
1133
 
 
1134
static void
 
1135
_postfix_add_float(fvm_selector_postfix_t  *pf,
 
1136
                   double                   val)
 
1137
{
 
1138
  size_t add_size = _postfix_type_size + _postfix_float_size;
 
1139
 
 
1140
  /* Update postfix */
 
1141
 
 
1142
  if (pf->size + add_size > pf->max_size)
 
1143
    _postfix_grow(pf, pf->size + add_size);
 
1144
 
 
1145
  *((_postfix_type_t *)(pf->elements + pf->size)) = PF_FLOAT;
 
1146
  *((double *)(pf->elements + pf->size + _postfix_type_size)) = val;
 
1147
 
 
1148
  pf->size += add_size;
 
1149
}
 
1150
 
 
1151
/*----------------------------------------------------------------------------
 
1152
 * Add missing operand to postfix string structure
 
1153
 *
 
1154
 * parameters:
 
1155
 *   pf      <-> posfix string
 
1156
 *   missing <-- name of missing operand
 
1157
 *----------------------------------------------------------------------------*/
 
1158
 
 
1159
static void
 
1160
_postfix_add_missing(fvm_selector_postfix_t  *pf,
 
1161
                     const char              *missing)
 
1162
{
 
1163
  int n = pf->n_missing_operands;
 
1164
 
 
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++;
 
1169
}
 
1170
 
 
1171
/*----------------------------------------------------------------------------
 
1172
 * Check if a string defines an integer and scan its value
 
1173
 *
 
1174
 * parameters:
 
1175
 *   str   <-- string parsed
 
1176
 *   value --> integer conversion
 
1177
 *
 
1178
 * returns:
 
1179
 *   true if the string defines an integer, false otherwise
 
1180
 *----------------------------------------------------------------------------*/
 
1181
 
 
1182
static _Bool
 
1183
_is_int(const char  *str,
 
1184
        int         *value)
 
1185
{
 
1186
  int _value;
 
1187
  int retcode, int_len;
 
1188
 
 
1189
  *value = 0;
 
1190
  retcode = (_Bool)(sscanf(str, "%i%n", &_value, &int_len));
 
1191
 
 
1192
  if (retcode) {
 
1193
    if (int_len != (int)strlen(str))
 
1194
      retcode = 0;
 
1195
  }
 
1196
 
 
1197
  if (retcode)
 
1198
    *value = _value;
 
1199
 
 
1200
  return retcode;
 
1201
}
 
1202
 
 
1203
/*----------------------------------------------------------------------------
 
1204
 * Check if a string defines a floating-point number and scan its value
 
1205
 *
 
1206
 * parameters:
 
1207
 *   str   <-- string parsed
 
1208
 *   value --> floating-point conversion
 
1209
 *
 
1210
 * returns:
 
1211
 *   true if the string defines a floating-point number, false otherwise
 
1212
 *----------------------------------------------------------------------------*/
 
1213
 
 
1214
static _Bool
 
1215
_is_float(const char  *str,
 
1216
          double      *value)
 
1217
{
 
1218
  float _value;
 
1219
  int retcode, flt_len;
 
1220
 
 
1221
  *value = 0.0;
 
1222
  retcode = (_Bool)(sscanf(str, "%f%n", &_value, &flt_len));
 
1223
 
 
1224
  if (retcode) {
 
1225
    if (flt_len != (int)strlen(str))
 
1226
      retcode = false;
 
1227
  }
 
1228
 
 
1229
  if (retcode)
 
1230
    *value = _value;
 
1231
 
 
1232
  return retcode;
 
1233
}
 
1234
 
 
1235
/*----------------------------------------------------------------------------
 
1236
 * Handle a parsing error.
 
1237
 *
 
1238
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
1247
 
 
1248
static void
 
1249
_parse_error(const char               *err_str,
 
1250
             const char               *valid_syntax,
 
1251
             const char               *infix,
 
1252
             const _tokenized_t       *te,
 
1253
             int                       token_id,
 
1254
             _stack_t                 *stack,
 
1255
             fvm_selector_postfix_t  **postfix)
 
1256
{
 
1257
  int infix_pos = -1;
 
1258
 
 
1259
  if (token_id > -1)
 
1260
    infix_pos = te->infix_id[token_id];
 
1261
 
 
1262
  _stack_empty(stack);
 
1263
  _postfix_destroy(postfix);
 
1264
 
 
1265
  if (getenv("FVM_SELECTOR_DEBUG")) {
 
1266
    _parser_dump(_parser);
 
1267
    _dump_tokenized(infix, *te);
 
1268
  }
 
1269
 
 
1270
  if (infix_pos > -1) {
 
1271
 
 
1272
    int i;
 
1273
    char *infix_string_marker = NULL;
 
1274
 
 
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';
 
1280
 
 
1281
    if (valid_syntax != NULL)
 
1282
      bft_error(__FILE__, __LINE__, 0,
 
1283
                _("Error parsing expression:\n"
 
1284
                  "%s\n"
 
1285
                  "%s\n"
 
1286
                  "%s\n\n"
 
1287
                  "Valid (expected) syntax:\n\n"
 
1288
                  "%s"),
 
1289
                infix, infix_string_marker, err_str, valid_syntax);
 
1290
    else
 
1291
      bft_error(__FILE__, __LINE__, 0,
 
1292
                _("Error parsing expression:\n"
 
1293
                  "%s\n"
 
1294
                  "%s\n"
 
1295
                  "%s"),
 
1296
                infix, infix_string_marker, err_str);
 
1297
 
 
1298
    BFT_FREE(infix_string_marker);
 
1299
  }
 
1300
 
 
1301
  else {
 
1302
 
 
1303
    if (valid_syntax != NULL)
 
1304
      bft_error(__FILE__, __LINE__, 0,
 
1305
                _("Error parsing expression:\n"
 
1306
                  "%s\n"
 
1307
                  "%s\n"
 
1308
                  "Valid (expected) syntax:\n\n"
 
1309
                  "%s"),
 
1310
                infix, err_str, valid_syntax);
 
1311
    else
 
1312
      bft_error(__FILE__, __LINE__, 0,
 
1313
                _("Error parsing expression:\n"
 
1314
                  "%s\n"
 
1315
                  "%s"),
 
1316
                infix, err_str);
 
1317
 
 
1318
  }
 
1319
}
 
1320
 
 
1321
/*----------------------------------------------------------------------------
 
1322
 * Check for left / right operands for unary or binary operators
 
1323
 *
 
1324
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
1333
 
 
1334
static void
 
1335
_check_left_right(const char               *infix,
 
1336
                  const _tokenized_t       *te,
 
1337
                  int                       token_id,
 
1338
                  _operator_type_t          otype,
 
1339
                  _Bool                     has_r_operand,
 
1340
                  _stack_t                 *os,
 
1341
                  fvm_selector_postfix_t  **postfix)
 
1342
{
 
1343
  int i;
 
1344
 
 
1345
  if (otype != OT_L_PAREN && otype != OT_UNARY && otype != OT_BINARY)
 
1346
    return;
 
1347
 
 
1348
  i = token_id+1;
 
1349
 
 
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);
 
1355
 
 
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);
 
1362
}
 
1363
 
 
1364
/*----------------------------------------------------------------------------
 
1365
 * Find a group or attribute corresponding to a token
 
1366
 *
 
1367
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
1377
 
 
1378
static void
 
1379
_find_group_or_attribute(int          n_groups,
 
1380
                         int          n_attributes,
 
1381
                         const char  *group_name[],
 
1382
                         const int    attribute[],
 
1383
                         const char  *token,
 
1384
                         _Bool        protected,
 
1385
                         int         *group_id,
 
1386
                         int         *attribute_id)
 
1387
{
 
1388
  int att_cmp, start_id, end_id;
 
1389
 
 
1390
  /* Initialize return values */
 
1391
 
 
1392
  *group_id = -1;
 
1393
  *attribute_id = -1;
 
1394
 
 
1395
  /* Test for attributes first */
 
1396
 
 
1397
  if (protected == false) {
 
1398
 
 
1399
    int val;
 
1400
 
 
1401
    if (_is_int(token, &val) && n_attributes > 0) {
 
1402
 
 
1403
      start_id = 0;
 
1404
      end_id = n_attributes - 1;
 
1405
 
 
1406
      /* use binary search */
 
1407
 
 
1408
      while (start_id <= end_id) {
 
1409
        int mid_id = start_id + ((end_id - start_id) / 2);
 
1410
        att_cmp = attribute[mid_id];
 
1411
        if (att_cmp < val)
 
1412
          start_id = mid_id + 1;
 
1413
        else if (att_cmp > val)
 
1414
          end_id = mid_id - 1;
 
1415
        else {
 
1416
          *attribute_id = mid_id;
 
1417
          return;
 
1418
        }
 
1419
 
 
1420
      }
 
1421
 
 
1422
    }
 
1423
 
 
1424
  }
 
1425
 
 
1426
  /* Test for groups if no attributes found */
 
1427
 
 
1428
  if (n_groups == 0)
 
1429
    return;
 
1430
 
 
1431
  start_id = 0;
 
1432
  end_id = n_groups - 1;
 
1433
 
 
1434
  /* use binary search */
 
1435
 
 
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);
 
1439
    if (att_cmp < 0)
 
1440
      start_id = mid_id + 1;
 
1441
    else if (att_cmp > 0)
 
1442
      end_id = mid_id - 1;
 
1443
    else {
 
1444
      *group_id = mid_id;
 
1445
      return;
 
1446
    }
 
1447
  }
 
1448
}
 
1449
 
 
1450
/*----------------------------------------------------------------------------
 
1451
 * Determine if tokens define a group range
 
1452
 *
 
1453
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
1459
 
 
1460
static void
 
1461
_group_range(int          n_groups,
 
1462
             const char  *group_name[],
 
1463
             const char  *token[2],
 
1464
             int          group_id[2])
 
1465
{
 
1466
  int i, att_cmp, start_id, end_id, mid_id;
 
1467
 
 
1468
  /* Initialize return values */
 
1469
 
 
1470
  group_id[0] = -1;
 
1471
  group_id[1] = -1;
 
1472
 
 
1473
  /* Test for groups */
 
1474
 
 
1475
  if (n_groups > 0) {
 
1476
 
 
1477
    if (strcmp(token[0], token[1]) > 0) {
 
1478
      const char *_tmp = token[0];
 
1479
      token[0] = token[1];
 
1480
      token[1] = _tmp;
 
1481
    }
 
1482
 
 
1483
    for (i = 0; i < 2; i++) {
 
1484
 
 
1485
      start_id = 0;
 
1486
      end_id = n_groups - 1;
 
1487
      mid_id = (end_id - start_id) / 2;
 
1488
 
 
1489
      /* use binary search */
 
1490
 
 
1491
      while (start_id < end_id) {
 
1492
        att_cmp = strcmp(group_name[mid_id], token[i]);
 
1493
        if (att_cmp < 0)
 
1494
          start_id = mid_id + 1;
 
1495
        else if (att_cmp > 0)
 
1496
          end_id = mid_id - 1;
 
1497
        else
 
1498
          break;
 
1499
        mid_id = start_id + ((end_id - start_id) / 2);
 
1500
      }
 
1501
 
 
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;
 
1508
 
 
1509
    }
 
1510
 
 
1511
    if (   group_id[0] >= n_groups
 
1512
        || group_id[1] < 0) {
 
1513
      group_id[0] = -1;
 
1514
      group_id[1] = -1;
 
1515
    }
 
1516
    else if (group_id[1] >= n_groups)
 
1517
      group_id[1] -= 1;
 
1518
 
 
1519
  }
 
1520
 
 
1521
}
 
1522
 
 
1523
/*----------------------------------------------------------------------------
 
1524
 * Determine if tokens define an atribute range
 
1525
 *
 
1526
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
1532
 
 
1533
static void
 
1534
_attribute_range(int          n_attributes,
 
1535
                 const int    attribute[],
 
1536
                 const char  *token[2],
 
1537
                 int          attribute_id[2])
 
1538
{
 
1539
  int i, att_cmp, start_id, end_id, mid_id;
 
1540
  int val[2];
 
1541
 
 
1542
  /* Initialize return values */
 
1543
 
 
1544
  attribute_id[0] = -1;
 
1545
  attribute_id[1] = -1;
 
1546
 
 
1547
  /* Test for attributes */
 
1548
 
 
1549
  if (   n_attributes > 0
 
1550
      && _is_int(token[0], val) && _is_int(token[1], val + 1)) {
 
1551
 
 
1552
    if (val[0] > val[1]) {
 
1553
      int _tmp = val[0];
 
1554
      val[0] = val[1];
 
1555
      val[1] = _tmp;
 
1556
    }
 
1557
 
 
1558
    for (i = 0; i < 2; i++) {
 
1559
 
 
1560
      start_id = 0;
 
1561
      end_id = n_attributes - 1;
 
1562
      mid_id = (end_id - start_id) / 2;
 
1563
 
 
1564
      /* use binary search */
 
1565
 
 
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;
 
1572
        else
 
1573
          break;
 
1574
        mid_id = start_id + ((end_id - start_id) / 2);
 
1575
      }
 
1576
 
 
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;
 
1582
 
 
1583
    }
 
1584
 
 
1585
    if (   attribute_id[0] >= n_attributes
 
1586
        || attribute_id[1] < 0) {
 
1587
      attribute_id[0] = -1;
 
1588
      attribute_id[1] = -1;
 
1589
    }
 
1590
    else if (attribute_id[1] >= n_attributes)
 
1591
      attribute_id[1] -= 1;
 
1592
 
 
1593
  }
 
1594
 
 
1595
}
 
1596
 
 
1597
/*----------------------------------------------------------------------------
 
1598
 * Handle geometric functions in a tokenized expression.
 
1599
 *
 
1600
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
1609
 
 
1610
static void
 
1611
_parse_geometric_args(_operator_code_t          opcode,
 
1612
                      const char               *infix,
 
1613
                      const _tokenized_t       *te,
 
1614
                      int                       token_start,
 
1615
                      int                       token_end,
 
1616
                      _stack_t                 *os,
 
1617
                      fvm_selector_postfix_t  **postfix)
 
1618
{
 
1619
  const char *tok;
 
1620
  int i = token_start;
 
1621
 
 
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;
 
1629
 
 
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>]");
 
1655
 
 
1656
  /* First parse for floating-point values */
 
1657
 
 
1658
  while (i < token_end && error == false) {
 
1659
 
 
1660
    tok =  te->tokens + te->token_id[i];
 
1661
 
 
1662
    if (_is_float(tok, val + n_vals)) {
 
1663
      tok =  te->tokens + te->token_id[++i];
 
1664
      n_vals++;
 
1665
      if (n_vals > 12)
 
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);
 
1670
        error = true;
 
1671
      }
 
1672
      else
 
1673
        i++;
 
1674
    }
 
1675
    else
 
1676
      break;
 
1677
 
 
1678
  }
 
1679
 
 
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);
 
1683
 
 
1684
  /* Initialize error reporting function syntax,
 
1685
     check number of floating-point arguments,
 
1686
     and normalize normals. */
 
1687
 
 
1688
  switch(opcode) {
 
1689
 
 
1690
  case OC_NORMAL:
 
1691
    func_syntax = normals_syntax;
 
1692
    if (n_vals == 4) {
 
1693
      have_epsilon = true;
 
1694
      epsilon = val[n_vals-1];
 
1695
      n_vals--;
 
1696
    }
 
1697
    if (n_vals != 3)
 
1698
      error = true;
 
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;
 
1701
    break;
 
1702
 
 
1703
  case OC_PLANE:
 
1704
    func_syntax = plane_syntax;
 
1705
    if (n_vals == 5 || n_vals == 7) {
 
1706
      have_epsilon = true;
 
1707
      epsilon = val[n_vals-1];
 
1708
      n_vals--;
 
1709
    }
 
1710
    if (n_vals != 4 && n_vals != 6)
 
1711
      error = true;
 
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 */
 
1715
    if (n_vals == 4)
 
1716
      val[3] /= norm;
 
1717
    else { /* if (n_vals == 6) */
 
1718
      val[3] = - (val[0]*val[3] + val[1]*val[4] + val[2]*val[5]);
 
1719
      n_vals = 4;
 
1720
    }
 
1721
    break;
 
1722
 
 
1723
  case OC_BOX:
 
1724
    func_syntax = box_syntax;
 
1725
    if (n_vals != 6 && n_vals != 12)
 
1726
      error = true;
 
1727
    break;
 
1728
 
 
1729
  case OC_CYLINDER:
 
1730
    func_syntax = cylinder_syntax;
 
1731
    if (n_vals != 7)
 
1732
      error = true;
 
1733
    break;
 
1734
 
 
1735
  case OC_SPHERE:
 
1736
    func_syntax = sphere_syntax;
 
1737
    if (n_vals != 4)
 
1738
      error = true;
 
1739
    break;
 
1740
 
 
1741
  default:
 
1742
    _parse_error(_("This geometric function is not implemented."),
 
1743
                 NULL, infix, te, token_start - 2, os, postfix);
 
1744
    break;
 
1745
  }
 
1746
 
 
1747
  if (error == true)
 
1748
    _parse_error(_("Wrong number of floating-point arguments."),
 
1749
                 _(func_syntax),
 
1750
                 infix, te, token_start, os, postfix);
 
1751
 
 
1752
  /* Check for one additional (key, value) arguments */
 
1753
 
 
1754
  if (i < token_end && error == false) {
 
1755
 
 
1756
    if ((opcode == OC_NORMAL || opcode == OC_PLANE) && have_epsilon == false) {
 
1757
 
 
1758
      if (strcmp(te->tokens + te->token_id[i], "epsilon") == 0) {
 
1759
        if (strcmp(te->tokens + te->token_id[i+1], "="))
 
1760
          error = true;
 
1761
        tok =  te->tokens + te->token_id[i+2];
 
1762
        if (_is_float(tok, &epsilon)) {
 
1763
          have_epsilon = true;
 
1764
          i += 3;
 
1765
        }
 
1766
        else {
 
1767
          _parse_error(_("Expected syntax:\n"
 
1768
                         "  epsilon = <value>\n"),
 
1769
                       NULL, infix, te, i, os, postfix);
 
1770
          error = true;
 
1771
        }
 
1772
      }
 
1773
 
 
1774
    }
 
1775
 
 
1776
    if (opcode == OC_PLANE && have_epsilon == false) {
 
1777
      if (strcmp(te->tokens + te->token_id[i], "inside") == 0) {
 
1778
        inout = -1;
 
1779
        i++;
 
1780
      }
 
1781
      else if (strcmp(te->tokens + te->token_id[i], "outside") == 0) {
 
1782
        inout = 1;
 
1783
        i++;
 
1784
      }
 
1785
    }
 
1786
 
 
1787
  }
 
1788
 
 
1789
  if (i < token_end) {
 
1790
    _parse_error(_("Unexpected argument(s)."),
 
1791
                 _(func_syntax),
 
1792
                 infix, te, i, os, postfix);
 
1793
  }
 
1794
 
 
1795
  /* Update postfix */
 
1796
 
 
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);
 
1802
  }
 
1803
  else {
 
1804
    (*postfix)->coords_dependency = true;
 
1805
    if (opcode == OC_PLANE) {
 
1806
      if (inout == 0)
 
1807
        val[n_vals++] = epsilon;
 
1808
      else
 
1809
        n_opts++;
 
1810
      assert(n_vals + n_opts == 5);
 
1811
    }
 
1812
  }
 
1813
 
 
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]);
 
1818
  if (n_opts == 1) {
 
1819
    assert (opcode == OC_PLANE && inout != 0);
 
1820
    _postfix_add_int(*postfix, inout, PF_INT);
 
1821
  }
 
1822
 
 
1823
}
 
1824
 
 
1825
/*----------------------------------------------------------------------------
 
1826
 * Check for and handle coordinate conditions in a tokenized expression.
 
1827
 *
 
1828
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
1841
 
 
1842
static void
 
1843
_parse_for_function(const _parser_t          *this_parser,
 
1844
                    const char               *infix,
 
1845
                    const _tokenized_t       *te,
 
1846
                    int                       n_groups,
 
1847
                    int                       n_attributes,
 
1848
                    const char               *group_name[],
 
1849
                    const int                 attribute[],
 
1850
                    int                      *token_id,
 
1851
                    _Bool                    *has_r_operand,
 
1852
                    _stack_t                 *os,
 
1853
                    fvm_selector_postfix_t  **postfix)
 
1854
{
 
1855
  const char *tok;
 
1856
  int i = *token_id + 1, j = 0, k = 0;
 
1857
  const _operator_t *op = NULL;
 
1858
 
 
1859
  if (te->n_tokens <= i)
 
1860
    return;
 
1861
 
 
1862
  tok = te->tokens + te->token_id[i];
 
1863
 
 
1864
  /* Pre-check syntax */
 
1865
 
 
1866
  if (te->protected[i] == true || strlen(tok) != 1)
 
1867
    return;
 
1868
 
 
1869
  if (tok[0] != '[')
 
1870
    return;
 
1871
 
 
1872
  /* If we arrived here, we have a function start */
 
1873
 
 
1874
  k = 1;
 
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) {
 
1878
      if (tok[0] == '[')
 
1879
        k++;
 
1880
      else if (tok[0] == ']')
 
1881
        k--;
 
1882
    }
 
1883
    if (k == 0)
 
1884
      break;
 
1885
  }
 
1886
  if (j == te->n_tokens) {
 
1887
    _parse_error(_("Missing closing ]."),
 
1888
                 NULL, infix, te, i, os, postfix);
 
1889
    return;
 
1890
  }
 
1891
 
 
1892
  /* We have a function-type syntax, so find the corresponding function */
 
1893
 
 
1894
  tok = te->tokens + te->token_id[*token_id];
 
1895
 
 
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];
 
1900
        break;
 
1901
      }
 
1902
    }
 
1903
  }
 
1904
 
 
1905
  if (op == NULL) {
 
1906
    _parse_error(_("Function arguments used with an unknown operator."),
 
1907
                 NULL, infix, te, *token_id, os, postfix);
 
1908
    return;
 
1909
  }
 
1910
  else if (op->type != OT_FUNCTION) {
 
1911
    _parse_error(_("Operator does not accept function arguments."),
 
1912
                 NULL, infix, te, *token_id, os, postfix);
 
1913
    return;
 
1914
  }
 
1915
 
 
1916
  *token_id = j + 1;
 
1917
  *has_r_operand = true;
 
1918
 
 
1919
  /* Handle general group selection operators */
 
1920
 
 
1921
  if (op->code == OC_ALL || op->code == OC_NO_GROUP) {
 
1922
    if (j != i+1)
 
1923
      _parse_error(_("Function requires 0 arguments."),
 
1924
                   NULL, infix, te, *token_id, os, postfix);
 
1925
    else
 
1926
      _postfix_add_opcode(*postfix, op->code);
 
1927
  }
 
1928
 
 
1929
  /* Handle range operator */
 
1930
 
 
1931
  else if (op->code == OC_RANGE) {
 
1932
 
 
1933
    const char *t[3] = {NULL, NULL, NULL};
 
1934
    _Bool force_group = false, force_attrib = false, error = false;
 
1935
 
 
1936
    i++;
 
1937
    k = 0;
 
1938
    while (i < j && k < 3) {
 
1939
      t[k++] = te->tokens + te->token_id[i];
 
1940
      i++;
 
1941
      if (i < j) {
 
1942
        if (strcmp(te->tokens + te->token_id[i], ","))
 
1943
          error = true;
 
1944
        else {
 
1945
          i++;
 
1946
          if (i == j)
 
1947
            error = true;
 
1948
        }
 
1949
      }
 
1950
    }
 
1951
    if (i < j)
 
1952
      error = true;
 
1953
 
 
1954
    if (k == 3) {
 
1955
      if (strcmp(t[2], "group") == 0)
 
1956
        force_group = true;
 
1957
      else if (strcmp(t[2], "attribute") == 0)
 
1958
        force_attrib = true;
 
1959
      else
 
1960
        error = true;
 
1961
      k = 2;
 
1962
    }
 
1963
 
 
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);
 
1970
 
 
1971
 
 
1972
    else {
 
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;
 
1979
      else
 
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);
 
1985
      }
 
1986
      else {
 
1987
        _postfix_add_int(*postfix, -1, pf_type);
 
1988
        _postfix_add_missing(*postfix, t[0]);
 
1989
        _postfix_add_missing(*postfix, t[1]);
 
1990
      }
 
1991
    }
 
1992
 
 
1993
  }
 
1994
 
 
1995
  /* Handle geometric operators */
 
1996
 
 
1997
  else
 
1998
    _parse_geometric_args(op->code, infix, te, i+1, j, os, postfix);
 
1999
 
 
2000
}
 
2001
 
 
2002
/*----------------------------------------------------------------------------
 
2003
 * Check for and handle coordinate conditions in a tokenized expression.
 
2004
 *
 
2005
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
2013
 
 
2014
static void
 
2015
_parse_for_coord_conditions(const char               *infix,
 
2016
                            const _tokenized_t       *te,
 
2017
                            int                      *token_id,
 
2018
                            _Bool                    *has_r_operand,
 
2019
                            _stack_t                 *os,
 
2020
                            fvm_selector_postfix_t  **postfix)
 
2021
{
 
2022
  const char *t1;
 
2023
  size_t      t1_len;
 
2024
  double      val;
 
2025
  _Bool has_coord_cond = false;
 
2026
  int coord_id = -1;
 
2027
  int i = *token_id + 1, j = 0;
 
2028
 
 
2029
  if (te->n_tokens <= i)
 
2030
    return;
 
2031
 
 
2032
  t1 = te->tokens + te->token_id[i];
 
2033
  t1_len = strlen(t1);
 
2034
 
 
2035
  /* Pre-check syntax */
 
2036
 
 
2037
  if (te->protected[i] == true || t1_len == 0 || t1_len > 2)
 
2038
    return;
 
2039
 
 
2040
  if ((t1[0] != '<' && t1[0] != '>') || (t1_len == 2 && t1[1] != '='))
 
2041
    return;
 
2042
 
 
2043
  /* If we arrived here, we have a >, <, >=, or <= operator */
 
2044
 
 
2045
  if (te->n_tokens == i+1) {
 
2046
    _parse_error(_("Operator needs a right operand."),
 
2047
                 NULL, infix, te, i, os, postfix);
 
2048
    return;
 
2049
  }
 
2050
 
 
2051
  /* Try for coord_id, operator, value or value, operator, coord_id */
 
2052
 
 
2053
  for (j = 0; j < 2; j++) {
 
2054
 
 
2055
    const char *t2 = te->tokens + te->token_id[i - 1 + j*2];
 
2056
 
 
2057
    if (strlen(t2) == 1) {
 
2058
      if (*t2 == 'x' || *t2 == 'X')
 
2059
        coord_id = 0;
 
2060
      else if (*t2 == 'y' || *t2 == 'Y')
 
2061
        coord_id = 1;
 
2062
      else if (*t2 == 'z' || *t2 == 'Z')
 
2063
        coord_id = 2;
 
2064
    }
 
2065
    if (coord_id != -1)
 
2066
      break;
 
2067
  }
 
2068
 
 
2069
  if (j == 0)
 
2070
    has_coord_cond = _is_float(te->tokens + te->token_id[i + 1], &val);
 
2071
  else if (j == 1)
 
2072
    has_coord_cond = _is_float(te->tokens + te->token_id[i - 1], &val);
 
2073
 
 
2074
  /* If we have a valid syntax, add it to postfix */
 
2075
 
 
2076
  if (has_coord_cond) {
 
2077
 
 
2078
    _operator_code_t oc;
 
2079
 
 
2080
    /* Permute operator if necessery to always have a
 
2081
       {coord_id, operator, value} expression */
 
2082
 
 
2083
    if (j == 0) {
 
2084
      if (t1[0] == '<' )
 
2085
        oc = OC_LT;
 
2086
      else
 
2087
        oc = OC_GT;
 
2088
    }
 
2089
    else {
 
2090
      assert(j == 1);
 
2091
      if (t1[0] == '<' )
 
2092
        oc = OC_GT;
 
2093
      else
 
2094
        oc = OC_LT;
 
2095
    }
 
2096
    if (t1_len == 2) {
 
2097
      if (oc == OC_LT)
 
2098
        oc = OC_LE;
 
2099
      else
 
2100
        oc = OC_GE;
 
2101
    }
 
2102
 
 
2103
    _postfix_add_opcode(*postfix, oc);
 
2104
    _postfix_add_int(*postfix, coord_id, PF_INT);
 
2105
    _postfix_add_float(*postfix, val);
 
2106
 
 
2107
    i += 2;
 
2108
    *token_id = i;
 
2109
    *has_r_operand = true;
 
2110
    (*postfix)->coords_dependency = true;
 
2111
 
 
2112
  }
 
2113
  else {
 
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);
 
2117
    return;
 
2118
  }
 
2119
 
 
2120
  /* If we have a valid syntax with the coord_id on the
 
2121
     left, we may have a "1 < x <= 2" type syntax */
 
2122
 
 
2123
  if (has_coord_cond && j == 1 && te->n_tokens > i) {
 
2124
 
 
2125
    const char *t3 = te->tokens + te->token_id[i];
 
2126
    size_t      t3_len = strlen(t3);
 
2127
 
 
2128
    if (te->protected[i] == true || t3_len == 0 || t3_len > 2)
 
2129
      return;
 
2130
 
 
2131
    if (   (t3[0] != '<' && t3[0] != '>')
 
2132
        || (t3_len == 2 && t3[1] != '='))
 
2133
      return;
 
2134
 
 
2135
    if (t3[0] != t1[0]) {
 
2136
      _parse_error(_("Inconsistant interval specification."),
 
2137
                   NULL, infix, te, i, os, postfix);
 
2138
      return;
 
2139
    }
 
2140
    else if (te->n_tokens == i+1) {
 
2141
      _parse_error(_("Operator needs a right operand."),
 
2142
                   NULL, infix, te, i, os, postfix);
 
2143
      return;
 
2144
    }
 
2145
 
 
2146
    has_coord_cond = _is_float(te->tokens + te->token_id[i + 1], &val);
 
2147
 
 
2148
    /* If we have a valid syntax, add it to postfix */
 
2149
 
 
2150
    if (has_coord_cond) {
 
2151
 
 
2152
      _operator_code_t oc;
 
2153
 
 
2154
      /* No permutation necessary here */
 
2155
 
 
2156
      if (t3[0] == '<' )
 
2157
        oc = OC_LT;
 
2158
      else
 
2159
        oc = OC_GT;
 
2160
      if (t1_len == 2) {
 
2161
        if (oc == OC_LT)
 
2162
          oc = OC_LE;
 
2163
        else
 
2164
        oc = OC_GE;
 
2165
      }
 
2166
 
 
2167
      _postfix_add_opcode(*postfix, oc);
 
2168
      _postfix_add_int(*postfix, coord_id, PF_INT);
 
2169
      _postfix_add_float(*postfix, val);
 
2170
 
 
2171
      /* Add implicit and here */
 
2172
 
 
2173
      _postfix_add_opcode(*postfix, OC_AND);
 
2174
 
 
2175
      i += 2;
 
2176
      *token_id = i;
 
2177
 
 
2178
    }
 
2179
    else {
 
2180
      _parse_error(_("Operator needs a floating point operand"),
 
2181
                   NULL, infix, te, i, os, postfix);
 
2182
      return;
 
2183
    }
 
2184
 
 
2185
  }
 
2186
}
 
2187
 
 
2188
/*----------------------------------------------------------------------------
 
2189
 * Parse a tokenized expression string.
 
2190
 *
 
2191
 * parameters:
 
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)
 
2199
 *
 
2200
 * returns:
 
2201
 *   pointer to created postfix structure
 
2202
 *----------------------------------------------------------------------------*/
 
2203
 
 
2204
static fvm_selector_postfix_t *
 
2205
_parse_tokenized(const _parser_t     *this_parser,
 
2206
                 const char          *infix,
 
2207
                 const _tokenized_t  *te,
 
2208
                 int                  n_groups,
 
2209
                 int                  n_attributes,
 
2210
                 const char          *group_name[],
 
2211
                 const int            attribute[])
 
2212
{
 
2213
  int i, j;
 
2214
  _stack_t os;
 
2215
  _Bool has_r_operand = false;
 
2216
  fvm_selector_postfix_t *pf = NULL;
 
2217
 
 
2218
  /* Initialization */
 
2219
 
 
2220
  _stack_initialize(&os);
 
2221
 
 
2222
  pf = _postfix_create(infix);
 
2223
 
 
2224
  /* Loop on tokens */
 
2225
 
 
2226
  i = 0;
 
2227
 
 
2228
  while (i < te->n_tokens) {
 
2229
 
 
2230
    const char *tok;
 
2231
    const _operator_t *op_1 = NULL;
 
2232
 
 
2233
    /* Look ahead to handle functions and "<", "<=", ">", ">=" syntax */
 
2234
 
 
2235
    _parse_for_function(this_parser,
 
2236
                        infix,
 
2237
                        te,
 
2238
                        n_groups,
 
2239
                        n_attributes,
 
2240
                        group_name,
 
2241
                        attribute,
 
2242
                        &i,
 
2243
                        &has_r_operand,
 
2244
                        &os,
 
2245
                        &pf);
 
2246
    _parse_for_coord_conditions(infix, te, &i, &has_r_operand, &os, &pf);
 
2247
 
 
2248
    if (i == te->n_tokens)
 
2249
      break;
 
2250
 
 
2251
    /* Now handle token */
 
2252
 
 
2253
    tok = te->tokens + te->token_id[i];
 
2254
 
 
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];
 
2259
          break;
 
2260
        }
 
2261
      }
 
2262
    }
 
2263
 
 
2264
    /* Basic check for left / right operands to operators */
 
2265
 
 
2266
    if (op_1 != NULL)
 
2267
      _check_left_right(infix, te, i, op_1->type, has_r_operand, &os, &pf);
 
2268
 
 
2269
    /* Now add to postfix or stack */
 
2270
 
 
2271
    if (op_1 == NULL) {
 
2272
 
 
2273
      int  group_id, attribute_id;
 
2274
 
 
2275
      /* If two operands follow each other, we have a parse error */
 
2276
 
 
2277
      if (has_r_operand == true)
 
2278
        _parse_error(_("Expected operator instead of operand."),
 
2279
                     NULL, infix, te, i, &os, &pf);
 
2280
 
 
2281
      /* Now add entry to postfix */
 
2282
 
 
2283
      _find_group_or_attribute(n_groups,
 
2284
                               n_attributes,
 
2285
                               group_name,
 
2286
                               attribute,
 
2287
                               tok,
 
2288
                               te->protected[i],
 
2289
                               &group_id,
 
2290
                               &attribute_id);
 
2291
 
 
2292
      if (attribute_id > -1)
 
2293
        _postfix_add_int(pf, attribute_id, PF_ATTRIBUTE_ID);
 
2294
      else
 
2295
        _postfix_add_int(pf, group_id, PF_GROUP_ID);
 
2296
 
 
2297
      if (attribute_id == -1 && group_id == -1)
 
2298
        _postfix_add_missing(pf, tok);
 
2299
 
 
2300
    }
 
2301
    else {
 
2302
 
 
2303
      switch(op_1->type) {
 
2304
 
 
2305
      case OT_L_PAREN:
 
2306
        _stack_push(&os, op_1, i);
 
2307
        break;
 
2308
 
 
2309
      case OT_R_PAREN:
 
2310
        {
 
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);
 
2315
            op_2 = e.op;
 
2316
            if (op_2->type == OT_L_PAREN) {
 
2317
              matched = true;
 
2318
              break;
 
2319
            }
 
2320
            else {
 
2321
              _postfix_add_opcode(pf, op_2->code);
 
2322
            }
 
2323
          }
 
2324
          if (matched == false)
 
2325
            _parse_error(_("Parenthesis mismatch"),
 
2326
                         NULL, infix, te, i, &os, &pf);
 
2327
        }
 
2328
        break;
 
2329
 
 
2330
        /* At this stage, a function or "<", "<=", ">", ">=" syntax should
 
2331
           have been handled, so we have a syntax error here*/
 
2332
 
 
2333
      case OT_COORD_CONDITION:
 
2334
      case OT_FUNCTION:
 
2335
        _parse_error(_("Syntax error, probably due to misplaced operands."),
 
2336
                     NULL, infix, te, i, &os, &pf);
 
2337
        break;
 
2338
 
 
2339
      default:
 
2340
        {
 
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);
 
2346
            }
 
2347
            else
 
2348
              break;
 
2349
          }
 
2350
          _stack_push(&os, op_1, i);
 
2351
        }
 
2352
      } /* End of switch on operator type */
 
2353
 
 
2354
    }
 
2355
 
 
2356
    i++;
 
2357
 
 
2358
    has_r_operand = true;
 
2359
    if (op_1 != NULL) {
 
2360
      if (op_1->type != OT_R_PAREN && op_1->type != OT_FUNCTION)
 
2361
        has_r_operand = false;
 
2362
    }
 
2363
 
 
2364
  } /* End of loop on tokens */
 
2365
 
 
2366
  while (_stack_size(&os) > 0) {
 
2367
 
 
2368
    _stack_entry_t e = _stack_pop(&os);
 
2369
    const _operator_t *op = e.op;
 
2370
 
 
2371
    if (op->type == OT_L_PAREN)
 
2372
      _parse_error(_("Parenthesis mismatch"),
 
2373
                   NULL, infix, te, e.token_id, &os, &pf);
 
2374
    else {
 
2375
      _postfix_add_opcode(pf, op->code);
 
2376
    }
 
2377
 
 
2378
  }
 
2379
 
 
2380
  _postfix_adjust(pf);
 
2381
 
 
2382
  return pf;
 
2383
}
 
2384
 
 
2385
/*----------------------------------------------------------------------------
 
2386
 * Evaluate normal[] function conditions in a postfix expression
 
2387
 *
 
2388
 * parameters:
 
2389
 *   pf        <-- pointer to postfix structure
 
2390
 *   normal    <-- normal associated with evaluation
 
2391
 *   i         <-> current position in expression being evaluated
 
2392
 *
 
2393
 * returns:
 
2394
 *   true or false depending on evaluation
 
2395
 *----------------------------------------------------------------------------*/
 
2396
 
 
2397
static inline _Bool
 
2398
_eval_normal(const fvm_selector_postfix_t  *pf,
 
2399
             const double                   normal[],
 
2400
             size_t                        *i)
 
2401
{
 
2402
  double dotp;
 
2403
  double val[4];
 
2404
  int j;
 
2405
  const int n_vals = 4; /* 3 values for coordinates, 1 for tolerance */
 
2406
  _Bool retval = false;
 
2407
 
 
2408
  assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
 
2409
  assert(*((int *)(pf->elements + *i + _postfix_type_size)) == n_vals);
 
2410
 
 
2411
  *i += _postfix_type_size + _postfix_int_size + _postfix_type_size;
 
2412
 
 
2413
  for (j = 0; j < n_vals; j++) {
 
2414
    assert(*((_postfix_type_t *)(pf->elements + *i - _postfix_type_size))
 
2415
           == PF_FLOAT);
 
2416
    val[j] = *((double *)(pf->elements + *i));
 
2417
    *i += _postfix_float_size + _postfix_type_size;
 
2418
  }
 
2419
  *i -= _postfix_type_size;
 
2420
 
 
2421
  dotp = normal[0]*val[0] + normal[1]*val[1] + normal[2]*val[2];
 
2422
 
 
2423
  if (dotp > 0) {
 
2424
    double cos2 = dotp*dotp / (  normal[0]*normal[0]
 
2425
                               + normal[1]*normal[1]
 
2426
                               + normal[2]*normal[2]);
 
2427
    if (cos2 > val[3])
 
2428
      retval = true;
 
2429
  }
 
2430
 
 
2431
  return retval;
 
2432
}
 
2433
 
 
2434
/*----------------------------------------------------------------------------
 
2435
 * Evaluate plane[] function conditions in a postfix expression
 
2436
 *
 
2437
 * parameters:
 
2438
 *   pf        <-- pointer to postfix structure
 
2439
 *   coords    <-- coordinates associated with evaluation
 
2440
 *   i         <-> current position in expression being evaluated
 
2441
 *
 
2442
 * returns:
 
2443
 *   true or false depending on evaluation
 
2444
 *----------------------------------------------------------------------------*/
 
2445
 
 
2446
static inline _Bool
 
2447
_eval_plane(const fvm_selector_postfix_t  *pf,
 
2448
            const double                   coords[],
 
2449
            size_t                        *i)
 
2450
{
 
2451
  double pfunc;
 
2452
  double val[4];
 
2453
  int j;
 
2454
  _postfix_type_t pf_type;
 
2455
  _Bool retval = false;
 
2456
 
 
2457
  assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
 
2458
  assert(*((int *)(pf->elements + *i + _postfix_type_size)) == 5);
 
2459
 
 
2460
  /* 4 first arguments are always  floating-point
 
2461
     (plane equation coefficients) */
 
2462
 
 
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))
 
2466
           == PF_FLOAT);
 
2467
    val[j] = *((double *)(pf->elements + *i));
 
2468
    *i += _postfix_float_size + _postfix_type_size;
 
2469
  }
 
2470
  *i -= _postfix_type_size;
 
2471
 
 
2472
  pfunc = val[0]*coords[0] + val[1]*coords[1] + val[2]*coords[2] + val[3];
 
2473
 
 
2474
  /* Last argument may be floating-point or interger */
 
2475
 
 
2476
  pf_type = *((_postfix_type_t *)(pf->elements + *i));
 
2477
  *i += _postfix_type_size;
 
2478
 
 
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))
 
2485
      retval = true;
 
2486
  }
 
2487
  else {
 
2488
    double epsilon = *((double *)(pf->elements + *i));
 
2489
    assert(pf_type == PF_FLOAT);
 
2490
    *i += _postfix_float_size;
 
2491
    if (FVM_ABS(pfunc) < epsilon)
 
2492
      retval = true;
 
2493
  }
 
2494
 
 
2495
  return retval;
 
2496
}
 
2497
 
 
2498
/*----------------------------------------------------------------------------
 
2499
 * Evaluate box[] function conditions in a postfix expression
 
2500
 *
 
2501
 * parameters:
 
2502
 *   pf        <-- pointer to postfix structure
 
2503
 *   coords    <-- coordinates associated with evaluation
 
2504
 *   i         <-> current position in expression being evaluated
 
2505
 *
 
2506
 * returns:
 
2507
 *   true or false depending on evaluation
 
2508
 *----------------------------------------------------------------------------*/
 
2509
 
 
2510
static inline _Bool
 
2511
_eval_box(const fvm_selector_postfix_t  *pf,
 
2512
          const double                   coords[],
 
2513
          size_t                        *i)
 
2514
{
 
2515
  double val[12];
 
2516
  int j;
 
2517
  int n_vals; /* number of box coefficients */
 
2518
  _Bool retval = false;
 
2519
 
 
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);
 
2523
 
 
2524
  /* all arguments are floating-point */
 
2525
 
 
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))
 
2529
           == PF_FLOAT);
 
2530
    val[j] = *((double *)(pf->elements + *i));
 
2531
    *i += _postfix_float_size + _postfix_type_size;
 
2532
  }
 
2533
  *i -= _postfix_type_size;
 
2534
 
 
2535
  /* Geometric test */
 
2536
 
 
2537
  if (n_vals == 6) {
 
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])
 
2540
      retval = true;
 
2541
  }
 
2542
  else {
 
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)
 
2555
      retval = true;
 
2556
  }
 
2557
 
 
2558
  return retval;
 
2559
}
 
2560
 
 
2561
/*----------------------------------------------------------------------------
 
2562
 * Evaluate cylinder[] function conditions in a postfix expression
 
2563
 *
 
2564
 * parameters:
 
2565
 *   pf        <-- pointer to postfix structure
 
2566
 *   coords    <-- coordinates associated with evaluation
 
2567
 *   i         <-> current position in expression being evaluated
 
2568
 *
 
2569
 * returns:
 
2570
 *   true or false depending on evaluation
 
2571
 *----------------------------------------------------------------------------*/
 
2572
 
 
2573
static inline _Bool
 
2574
_eval_cylinder(const fvm_selector_postfix_t  *pf,
 
2575
               const double                   coords[],
 
2576
               size_t                        *i)
 
2577
{
 
2578
  double val[7];
 
2579
  int j;
 
2580
  const int n_vals = 7; /* number of cylinder coefficients */
 
2581
  _Bool retval = false;
 
2582
 
 
2583
  assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
 
2584
  assert(*((int *)(pf->elements + *i + _postfix_type_size)) == n_vals);
 
2585
 
 
2586
  /* all arguments are floating-point */
 
2587
 
 
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))
 
2591
           == PF_FLOAT);
 
2592
    val[j] = *((double *)(pf->elements + *i));
 
2593
    *i += _postfix_float_size + _postfix_type_size;
 
2594
  }
 
2595
  *i -= _postfix_type_size;
 
2596
 
 
2597
  /* Geometric test */
 
2598
 
 
2599
  {
 
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])
 
2617
        retval = true;
 
2618
    }
 
2619
  }
 
2620
 
 
2621
  return retval;
 
2622
}
 
2623
 
 
2624
/*----------------------------------------------------------------------------
 
2625
 * Evaluate sphere[] function conditions in a postfix expression
 
2626
 *
 
2627
 * parameters:
 
2628
 *   pf        <-- pointer to postfix structure
 
2629
 *   coords    <-- coordinates associated with evaluation
 
2630
 *   i         <-> current position in expression being evaluated
 
2631
 *
 
2632
 * returns:
 
2633
 *   true or false depending on evaluation
 
2634
 *----------------------------------------------------------------------------*/
 
2635
 
 
2636
static inline _Bool
 
2637
_eval_sphere(const fvm_selector_postfix_t  *pf,
 
2638
             const double                   coords[],
 
2639
             size_t                        *i)
 
2640
{
 
2641
  double val[4];
 
2642
  int j;
 
2643
  const int n_vals = 4; /* number of sphere coefficients */
 
2644
  _Bool retval = false;
 
2645
 
 
2646
  assert(*((_postfix_type_t *)(pf->elements + *i)) == PF_INT);
 
2647
  assert(*((int *)(pf->elements + *i + _postfix_type_size)) == n_vals);
 
2648
 
 
2649
  /* all arguments are floating-point */
 
2650
 
 
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))
 
2654
           == PF_FLOAT);
 
2655
    val[j] = *((double *)(pf->elements + *i));
 
2656
    *i += _postfix_float_size + _postfix_type_size;
 
2657
  }
 
2658
  *i -= _postfix_type_size;
 
2659
 
 
2660
  /* Geometric test */
 
2661
 
 
2662
  {
 
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];
 
2667
    len2
 
2668
      = _coords[0]*_coords[0] + _coords[1]*_coords[1] + _coords[2]*_coords[2];
 
2669
    if (len2 <= val[3]*val[3])
 
2670
      retval = true;
 
2671
  }
 
2672
 
 
2673
  return retval;
 
2674
}
 
2675
 
 
2676
/*----------------------------------------------------------------------------
 
2677
 * Evaluate coordinate conditions in a postfix expression
 
2678
 *
 
2679
 * parameters:
 
2680
 *   pf        <-- pointer to postfix structure
 
2681
 *   coords    <-- coordinates associated with evaluation
 
2682
 *   i         <-> current position in expression being evaluated
 
2683
 *
 
2684
 * returns:
 
2685
 *   true or false depending on evaluation
 
2686
 *----------------------------------------------------------------------------*/
 
2687
 
 
2688
static inline _Bool
 
2689
_eval_coord_gt(const fvm_selector_postfix_t  *pf,
 
2690
               const double                   coords[],
 
2691
               size_t                        *i)
 
2692
{
 
2693
  double cmp_val;
 
2694
  int coord_id;
 
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))
 
2700
         == PF_FLOAT);
 
2701
  cmp_val = *((double *)(pf->elements + *i));
 
2702
  *i += _postfix_float_size;
 
2703
  return (coords[coord_id] > cmp_val ? true : false);
 
2704
}
 
2705
 
 
2706
static inline _Bool
 
2707
_eval_coord_lt(const fvm_selector_postfix_t  *pf,
 
2708
               const double                   coords[],
 
2709
               size_t                        *i)
 
2710
{
 
2711
  double cmp_val;
 
2712
  int coord_id;
 
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))
 
2718
         == PF_FLOAT);
 
2719
  cmp_val = *((double *)(pf->elements + *i));
 
2720
  *i += _postfix_float_size;
 
2721
  return (coords[coord_id] < cmp_val ? true : false);
 
2722
}
 
2723
 
 
2724
static inline _Bool
 
2725
_eval_coord_ge(const fvm_selector_postfix_t  *pf,
 
2726
               const double                   coords[],
 
2727
               size_t                        *i)
 
2728
{
 
2729
  double cmp_val;
 
2730
  int coord_id;
 
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))
 
2736
         == PF_FLOAT);
 
2737
  cmp_val = *((double *)(pf->elements + *i));
 
2738
  *i += _postfix_float_size;
 
2739
  return (coords[coord_id] >= cmp_val ? true : false);
 
2740
}
 
2741
 
 
2742
static inline _Bool
 
2743
_eval_coord_le(const fvm_selector_postfix_t  *pf,
 
2744
               const double                   coords[],
 
2745
               size_t                        *i)
 
2746
{
 
2747
  double cmp_val;
 
2748
  int coord_id;
 
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))
 
2754
         == PF_FLOAT);
 
2755
  cmp_val = *((double *)(pf->elements + *i));
 
2756
  *i += _postfix_float_size;
 
2757
  return (coords[coord_id] <= cmp_val ? true : false);
 
2758
}
 
2759
 
 
2760
/*============================================================================
 
2761
 * Public function definitions
 
2762
 *============================================================================*/
 
2763
 
 
2764
/*----------------------------------------------------------------------------
 
2765
 * Create a postfix expression from an infix expression
 
2766
 *
 
2767
 * parameters:
 
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)
 
2773
 *
 
2774
 * returns:
 
2775
 *   pointer to created postfix structure
 
2776
 *----------------------------------------------------------------------------*/
 
2777
 
 
2778
fvm_selector_postfix_t *
 
2779
fvm_selector_postfix_create(const char  *infix,
 
2780
                            int          n_groups,
 
2781
                            int          n_attributes,
 
2782
                            const char  *group_name[],
 
2783
                            const int    attribute[])
 
2784
{
 
2785
  _tokenized_t te = _tokenize(infix);
 
2786
  fvm_selector_postfix_t * pf = NULL;
 
2787
 
 
2788
  if (_n_parser_references == 0)
 
2789
    _parser = _parser_create();
 
2790
  _n_parser_references++;
 
2791
 
 
2792
  pf = _parse_tokenized(_parser,
 
2793
                        infix,
 
2794
                        &te,
 
2795
                        n_groups,
 
2796
                        n_attributes,
 
2797
                        group_name,
 
2798
                        attribute);
 
2799
 
 
2800
  _empty_tokenized(&te);
 
2801
 
 
2802
  /* Return postfix expression pointer */
 
2803
 
 
2804
  return pf;
 
2805
}
 
2806
 
 
2807
/*----------------------------------------------------------------------------
 
2808
 * Destroy a postfix expression
 
2809
 *
 
2810
 * parameters:
 
2811
 *   pf <-> pointer to postfix structure pointer
 
2812
 *----------------------------------------------------------------------------*/
 
2813
 
 
2814
void
 
2815
fvm_selector_postfix_destroy(fvm_selector_postfix_t  **postfix)
 
2816
{
 
2817
  assert(postfix != NULL);
 
2818
  assert(*postfix != NULL);
 
2819
 
 
2820
  _n_parser_references--;
 
2821
  if (_n_parser_references == 0)
 
2822
    _parser_destroy(&_parser);
 
2823
 
 
2824
  _postfix_destroy(postfix);
 
2825
}
 
2826
 
 
2827
/*----------------------------------------------------------------------------
 
2828
 * Return a pointer to the infix string associated with a postfix expression
 
2829
 *
 
2830
 * parameters:
 
2831
 *   pf <-- pointer to postfix structure
 
2832
 *
 
2833
 * returns:
 
2834
 *   pointer to original infix string
 
2835
 *----------------------------------------------------------------------------*/
 
2836
 
 
2837
const char *
 
2838
fvm_selector_postfix_get_infix(const fvm_selector_postfix_t  *pf)
 
2839
{
 
2840
  assert(pf != NULL);
 
2841
 
 
2842
  return pf->infix;
 
2843
}
 
2844
 
 
2845
/*----------------------------------------------------------------------------
 
2846
 * Indicate if a postfix expression depends on coordinates
 
2847
 *
 
2848
 * parameters:
 
2849
 *   pf <-- pointer to postfix structure
 
2850
 *
 
2851
 * returns:
 
2852
 *   true if expression depends on coordinates, false otherwise
 
2853
 *----------------------------------------------------------------------------*/
 
2854
 
 
2855
_Bool
 
2856
fvm_selector_postfix_coords_dep(const fvm_selector_postfix_t  *pf)
 
2857
{
 
2858
  assert(pf != NULL);
 
2859
 
 
2860
  return pf->coords_dependency;
 
2861
}
 
2862
 
 
2863
/*----------------------------------------------------------------------------
 
2864
 * Indicate if a postfix expression depends on normals
 
2865
 *
 
2866
 * parameters:
 
2867
 *   pf <-- pointer to postfix structure
 
2868
 *
 
2869
 * returns:
 
2870
 *   true if expression depends on normals, false otherwise
 
2871
 *----------------------------------------------------------------------------*/
 
2872
 
 
2873
_Bool
 
2874
fvm_selector_postfix_normals_dep(const fvm_selector_postfix_t  *pf)
 
2875
{
 
2876
  assert(pf != NULL);
 
2877
 
 
2878
  return pf->normals_dependency;
 
2879
}
 
2880
 
 
2881
/*----------------------------------------------------------------------------
 
2882
 * Return the number of operands associated with a postfix expression
 
2883
 * missing in the associated group class set
 
2884
 *
 
2885
 * parameters:
 
2886
 *   pf <-- pointer to postfix structure
 
2887
 *
 
2888
 * returns:
 
2889
 *   number of missing operands
 
2890
 *----------------------------------------------------------------------------*/
 
2891
 
 
2892
int
 
2893
fvm_selector_postfix_n_missing(const fvm_selector_postfix_t  *pf)
 
2894
{
 
2895
  assert(pf != NULL);
 
2896
 
 
2897
  return pf->n_missing_operands;
 
2898
}
 
2899
 
 
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
 
2903
 *
 
2904
 * parameters:
 
2905
 *   pf <-- pointer to postfix structure
 
2906
 *   id <-- id of missing operand (0 to fvm_selector_postfix_n_missing())
 
2907
 *
 
2908
 * returns:
 
2909
 *   pointer to name of missing operand
 
2910
 *----------------------------------------------------------------------------*/
 
2911
 
 
2912
const char *
 
2913
fvm_selector_postfix_get_missing(const fvm_selector_postfix_t  *pf,
 
2914
                                 int                            id)
 
2915
{
 
2916
  const char *retval = NULL;
 
2917
  assert(pf != NULL);
 
2918
 
 
2919
  if (id > -1 && id < pf->n_missing_operands)
 
2920
    retval = pf->missing_operand[id];
 
2921
 
 
2922
  return retval;
 
2923
}
 
2924
 
 
2925
/*----------------------------------------------------------------------------
 
2926
 * Evaluate a postfix expression
 
2927
 *
 
2928
 * parameters:
 
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
 
2936
 *
 
2937
 * returns:
 
2938
 *   true or false base on expression evaluation
 
2939
 *----------------------------------------------------------------------------*/
 
2940
 
 
2941
_Bool
 
2942
fvm_selector_postfix_eval(const fvm_selector_postfix_t  *pf,
 
2943
                          int                            n_groups,
 
2944
                          int                            n_attributes,
 
2945
                          const int                      group_id[],
 
2946
                          const int                      attribute_id[],
 
2947
                          const double                   coords[],
 
2948
                          const double                   normal[])
 
2949
{
 
2950
  _Bool retval;
 
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;
 
2954
 
 
2955
  /* Evaluate postfix_string */
 
2956
 
 
2957
  i = 0;
 
2958
 
 
2959
  while (i < pf->size) {
 
2960
 
 
2961
    _postfix_type_t type = *((_postfix_type_t *)(pf->elements + i));
 
2962
 
 
2963
    i += _postfix_type_size;
 
2964
 
 
2965
    switch(type) {
 
2966
 
 
2967
    case PF_GROUP_ID:
 
2968
      {
 
2969
        int j;
 
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;
 
2976
            break;
 
2977
          }
 
2978
        }
 
2979
        eval_size++;
 
2980
      }
 
2981
      break;
 
2982
    case PF_ATTRIBUTE_ID:
 
2983
      {
 
2984
        int j;
 
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;
 
2991
            break;
 
2992
          }
 
2993
        }
 
2994
        eval_size++;
 
2995
      }
 
2996
      break;
 
2997
    case PF_OPCODE:
 
2998
      {
 
2999
        size_t min_eval_size;
 
3000
        _operator_code_t oc = *((_operator_code_t *)(pf->elements + i));
 
3001
        i += _postfix_opcode_size;
 
3002
 
 
3003
        if (oc == OC_NOT)
 
3004
          min_eval_size = 1;
 
3005
        else if (oc >= OC_AND && oc <= OC_XOR)
 
3006
          min_eval_size = 2;
 
3007
        else
 
3008
          min_eval_size = 0;
 
3009
 
 
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."));
 
3014
        }
 
3015
 
 
3016
        switch(oc) {
 
3017
 
 
3018
        case OC_NOT:
 
3019
          if (eval_stack[eval_size-1] == false)
 
3020
            eval_stack[eval_size-1] = true;
 
3021
          else
 
3022
            eval_stack[eval_size-1] = false;
 
3023
          break;
 
3024
        case OC_AND:
 
3025
          eval_stack[eval_size-2] = (   eval_stack[eval_size-2]
 
3026
                                     && eval_stack[eval_size-1]);
 
3027
          eval_size--;
 
3028
          break;
 
3029
        case OC_OR:
 
3030
          eval_stack[eval_size-2] = (   eval_stack[eval_size-2]
 
3031
                                     || eval_stack[eval_size-1]);
 
3032
          eval_size--;
 
3033
          break;
 
3034
        case OC_XOR:
 
3035
          if (eval_stack[eval_size-2] != eval_stack[eval_size-1])
 
3036
            eval_stack[eval_size-2] = true;
 
3037
          else
 
3038
            eval_stack[eval_size-2] = false;
 
3039
          eval_size--;
 
3040
          break;
 
3041
 
 
3042
        case OC_ALL:
 
3043
          eval_stack[eval_size] = true;
 
3044
          eval_size++;
 
3045
          break;
 
3046
        case OC_NO_GROUP:
 
3047
          if (n_groups == 0 && n_attributes == 0)
 
3048
            eval_stack[eval_size] = true;
 
3049
          else
 
3050
            eval_stack[eval_size] = false;
 
3051
          eval_size++;
 
3052
          break;
 
3053
 
 
3054
        case OC_RANGE:
 
3055
          {
 
3056
            _postfix_type_t type1, type2;
 
3057
            int val1, val2;
 
3058
 
 
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;
 
3067
 
 
3068
            if (type1 == PF_GROUP_ID && type1 == type2) {
 
3069
              int j;
 
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;
 
3074
                  break;
 
3075
                }
 
3076
              }
 
3077
            }
 
3078
            else if (type1 == PF_ATTRIBUTE_ID && type1 == type2) {
 
3079
              int j;
 
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;
 
3084
                  break;
 
3085
                }
 
3086
              }
 
3087
            }
 
3088
            else {
 
3089
              fvm_selector_postfix_dump(pf, 0, 0, NULL, NULL);
 
3090
              bft_error(__FILE__, __LINE__, 0,
 
3091
                        _("Postfix error: "
 
3092
                          "range arguments of different or incorrect type."));
 
3093
            }
 
3094
 
 
3095
          }
 
3096
          eval_size++;
 
3097
          break;
 
3098
 
 
3099
        case OC_NORMAL:
 
3100
          eval_stack[eval_size++] = _eval_normal(pf, normal, &i);
 
3101
          break;
 
3102
        case OC_PLANE:
 
3103
          eval_stack[eval_size++] = _eval_plane(pf, coords, &i);
 
3104
          break;
 
3105
        case OC_BOX:
 
3106
          eval_stack[eval_size++] = _eval_box(pf, coords, &i);
 
3107
          break;
 
3108
        case OC_CYLINDER:
 
3109
          eval_stack[eval_size++] = _eval_cylinder(pf, coords, &i);
 
3110
          break;
 
3111
        case OC_SPHERE:
 
3112
          eval_stack[eval_size++] = _eval_sphere(pf, coords, &i);
 
3113
          break;
 
3114
 
 
3115
        case OC_GT:
 
3116
          eval_stack[eval_size++] = _eval_coord_gt(pf, coords, &i);
 
3117
          break;
 
3118
        case OC_LT:
 
3119
          eval_stack[eval_size++] = _eval_coord_lt(pf, coords, &i);
 
3120
          break;
 
3121
        case OC_GE:
 
3122
          eval_stack[eval_size++] = _eval_coord_ge(pf, coords, &i);
 
3123
          break;
 
3124
        case OC_LE:
 
3125
          eval_stack[eval_size++] = _eval_coord_le(pf, coords, &i);
 
3126
          break;
 
3127
 
 
3128
        default:
 
3129
          bft_error(__FILE__, __LINE__, 0,
 
3130
                    _("Operator %s not currently implemented."),
 
3131
                    _operator_name[oc]);
 
3132
 
 
3133
        } /* End of inside (operator) switch */
 
3134
 
 
3135
      }
 
3136
      break;
 
3137
 
 
3138
    default:
 
3139
      fvm_selector_postfix_dump(pf, 0, 0, NULL, NULL);
 
3140
      bft_error(__FILE__, __LINE__, 0,
 
3141
                _("Postfix evaluation error."));
 
3142
    }
 
3143
 
 
3144
    if (eval_size == eval_max_size) {
 
3145
      eval_max_size *= 2;
 
3146
      if (eval_stack == _eval_stack)
 
3147
        BFT_MALLOC(eval_stack, eval_max_size, _Bool);
 
3148
      else
 
3149
        BFT_REALLOC(eval_stack, eval_max_size, _Bool);
 
3150
    }
 
3151
 
 
3152
  } /* End of loop on postfix elements */
 
3153
 
 
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."));
 
3158
  }
 
3159
 
 
3160
  retval = eval_stack[0];
 
3161
 
 
3162
  if (eval_stack != _eval_stack)
 
3163
    BFT_FREE(eval_stack);
 
3164
 
 
3165
  return retval;
 
3166
}
 
3167
 
 
3168
/*----------------------------------------------------------------------------
 
3169
 * Dump the contents of a postfix structure in human readable form
 
3170
 *
 
3171
 * parameters:
 
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
 *----------------------------------------------------------------------------*/
 
3178
 
 
3179
void
 
3180
fvm_selector_postfix_dump(const fvm_selector_postfix_t  *pf,
 
3181
                          int                            n_groups,
 
3182
                          int                            n_attributes,
 
3183
                          const char                    *group_name[],
 
3184
                          const int                      attribute[])
 
3185
{
 
3186
  size_t i = 0;
 
3187
 
 
3188
  bft_printf("\n"
 
3189
             "Postfix expression dump:\n"
 
3190
             "  Coordinates dependency:   %d\n"
 
3191
             "  Normals dependency:       %d\n"
 
3192
             "  Infix:\n"
 
3193
             "    %s\n"
 
3194
             "  Elements:\n",
 
3195
             (int)pf->coords_dependency,
 
3196
             (int)pf->normals_dependency,
 
3197
             pf->infix);
 
3198
 
 
3199
  /* Dump postfix_string */
 
3200
 
 
3201
  i = 0;
 
3202
 
 
3203
  while (i < pf->size) {
 
3204
 
 
3205
    _postfix_type_t type = *((_postfix_type_t *)(pf->elements + i));
 
3206
 
 
3207
    i += _postfix_type_size;
 
3208
 
 
3209
    switch(type) {
 
3210
    case PF_OPCODE:
 
3211
      {
 
3212
        _operator_code_t oc = *((_operator_code_t *)(pf->elements + i));
 
3213
        bft_printf("    %s\n", _operator_name[oc]);
 
3214
        i += _postfix_opcode_size;
 
3215
      }
 
3216
      break;
 
3217
    case PF_GROUP_ID:
 
3218
    case PF_ATTRIBUTE_ID:
 
3219
    case PF_INT:
 
3220
      {
 
3221
        int val = *((int *)(pf->elements + i));
 
3222
        if (type == PF_GROUP_ID) {
 
3223
          if (val < 0)
 
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]);
 
3227
          else
 
3228
            bft_printf("    %d (group id)\n");
 
3229
        }
 
3230
        else if (type == PF_ATTRIBUTE_ID) {
 
3231
          if (val < 0)
 
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]);
 
3235
          else
 
3236
            bft_printf("    %d (attribute id)\n");
 
3237
        }
 
3238
        else
 
3239
          bft_printf("    %d\n", val);
 
3240
        i += _postfix_int_size;
 
3241
      }
 
3242
      break;
 
3243
    case PF_FLOAT:
 
3244
      {
 
3245
        double val = *((double *)(pf->elements + i));
 
3246
        bft_printf("    %g\n", val);
 
3247
        i += _postfix_float_size;
 
3248
      }
 
3249
      break;
 
3250
    default:
 
3251
      assert(0);
 
3252
      break;
 
3253
    }
 
3254
 
 
3255
  }
 
3256
 
 
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]);
 
3262
  }
 
3263
 
 
3264
  bft_printf("\n");
 
3265
}
 
3266
 
 
3267
/*----------------------------------------------------------------------------*/
 
3268
 
 
3269
#ifdef __cplusplus
 
3270
}
 
3271
#endif /* __cplusplus */
 
3272