4
* \brief Build an interpreter for a mathematical expression
8
This file is part of Code_Saturne, a general-purpose CFD tool.
10
Copyright (C) 1998-2011 EDF S.A.
12
This program is free software; you can redistribute it and/or modify it under
13
the terms of the GNU General Public License as published by the Free Software
14
Foundation; either version 2 of the License, or (at your option) any later
17
This program is distributed in the hope that it will be useful, but WITHOUT
18
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
22
You should have received a copy of the GNU General Public License along with
23
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
24
Street, Fifth Floor, Boston, MA 02110-1301, USA.
27
/*----------------------------------------------------------------------------*/
29
/*----------------------------------------------------------------------------
30
* Standard C library headers
31
*----------------------------------------------------------------------------*/
39
/*----------------------------------------------------------------------------
41
*----------------------------------------------------------------------------*/
44
#include <bft_printf.h>
45
#include <bft_error.h>
47
/*----------------------------------------------------------------------------
49
*----------------------------------------------------------------------------*/
52
#include "mei_parser_glob.h"
53
#include "mei_parser.h"
55
/*----------------------------------------------------------------------------
56
* Header for the current file
57
*----------------------------------------------------------------------------*/
59
#include "mei_evaluate.h"
61
/*----------------------------------------------------------------------------*/
65
#endif /* __cplusplus */
67
/*----------------------------------------------------------------------------
68
* Local macro definitions
69
*----------------------------------------------------------------------------*/
72
* \brief Default modulo for hash table.
77
/*=============================================================================
78
* Specific pragmas to disable some unrelevant warnings
79
*============================================================================*/
81
/* Globally disable warning on float-comparisons (equality) for GCC and Intel
82
compilers as we do it on purpose (infinite precision algorithm). */
84
#if defined(__GNUC__) && !defined(__ICC)
85
#pragma GCC diagnostic ignored "-Wfloat-equal"
87
#pragma warning disable 1572
90
/*============================================================================
91
* Private function definitions
92
*============================================================================*/
95
* \brief Copy the symbol table pointer into the each node of the interpreter.
97
* \param [in] n node of the interpreter
98
* \param [in] h table of symbols
102
_init_symbol_table(mei_node_t *n,
109
/* Copy the symbol table pointer into the current node */
113
/* Search the next node in the interpreter */
115
if (n->flag == FUNC1) {
116
_init_symbol_table(n->type->func.op, h);
118
else if (n->flag == FUNC2 || n->flag == FUNC3 || n->flag == FUNC4) {
119
for (i = 0; i < n->type->funcx.nops; i++)
120
_init_symbol_table(n->type->funcx.op[i], h);
122
else if (n->flag == OPR) {
123
for (i = 0; i < n->type->opr.nops; i++)
124
_init_symbol_table(n->type->opr.op[i], h);
129
* \brief Return the number of errors related to the use of undefined symbol
132
* \param [in] p node of an interpreter
133
* \return number of undefined symbol
137
_check_symbol(mei_node_t *p)
150
if (mei_hash_table_lookup(p->ht, p->type->id.i) == NULL) {
152
/* bft_printf("Warning: identifier %s is unknown\n", p->type->id.i); */
153
/* bft_printf("- line: %i \n", p->type->id.l); */
154
/* bft_printf("- column: %i \n", p->type->id.c); */
156
BFT_REALLOC(mei_glob_label_list, mei_glob_ierr_list+1, char*);
157
BFT_REALLOC(mei_glob_line_list, mei_glob_ierr_list+1, int);
158
BFT_REALLOC(mei_glob_column_list, mei_glob_ierr_list+1, int);
160
l = strlen("Warning, identifier ")+1;
161
BFT_MALLOC(mei_glob_label_list[mei_glob_ierr_list], l, char);
162
strncpy(mei_glob_label_list[mei_glob_ierr_list], "Warning: identifier ", l);
164
l = l + strlen(p->type->id.i);
165
BFT_REALLOC(mei_glob_label_list[mei_glob_ierr_list], l, char);
166
strncat(mei_glob_label_list[mei_glob_ierr_list], p->type->id.i, l);
168
l = l + strlen(" is unknown.\n");
169
BFT_REALLOC(mei_glob_label_list[mei_glob_ierr_list], l, char);
170
strncat(mei_glob_label_list[mei_glob_ierr_list], " is unknown.\n", l);
172
mei_glob_line_list[mei_glob_ierr_list] = p->type->id.l;
173
mei_glob_column_list[mei_glob_ierr_list] = p->type->id.c;
175
mei_glob_ierr_list++;
182
if (mei_hash_table_lookup(p->ht, p->type->func.name) == NULL) {
184
/* it is normally impossible to arrive here */
185
/* because the parser has already checked function names */
187
bft_error(__FILE__, __LINE__, 0, "Error: _check_symbol\n");
191
return _check_symbol(p->type->func.op);
194
if (mei_hash_table_lookup(p->ht, p->type->funcx.name) == NULL) {
196
/* It is normally impossible to arrive here */
197
/* because the parser has already checked function names */
199
bft_error(__FILE__, __LINE__, 0, "Error: _check_symbol\n");
203
iok = _check_symbol(p->type->funcx.op[0]);
204
iok += _check_symbol(p->type->funcx.op[1]);
208
bft_error(__FILE__, __LINE__, 0, "not implemented yet \n");
212
bft_error(__FILE__, __LINE__, 0, "not implemented yet \n");
217
switch (p->type->opr.oper) {
220
iok = _check_symbol(p->type->opr.op[0]);
221
iok += _check_symbol(p->type->opr.op[1]);
222
if (p->type->opr.nops > 2)
223
iok += _check_symbol(p->type->opr.op[2]);
227
return _check_symbol(p->type->opr.op[0]);
230
mei_hash_table_insert(p->ht,
231
p->type->opr.op[0]->type->id.i,
238
return _check_symbol(p->type->opr.op[1]);
241
return _check_symbol(p->type->opr.op[0]);
244
return _check_symbol(p->type->opr.op[0]);
247
return _check_symbol(p->type->opr.op[0]);
250
iok = _check_symbol(p->type->opr.op[0]);
251
iok += _check_symbol(p->type->opr.op[1]);
256
bft_error(__FILE__, __LINE__, 0, "Error: _check_symbol\n");
262
* \brief Return the evaluation of the expression.
264
* \param [in] p node of an interpreter
265
* \return value of evaluated expression
269
_evaluate(mei_node_t *p)
280
return p->type->con.value;
283
return (mei_hash_table_lookup(p->ht, p->type->id.i))->data->value;
286
f1 = (mei_hash_table_lookup(p->ht, p->type->func.name))->data->func;
287
return f1(_evaluate(p->type->func.op));
290
f2 = (mei_hash_table_lookup(p->ht, p->type->funcx.name))->data->f2;
291
return f2(_evaluate(p->type->funcx.op[0]), _evaluate(p->type->funcx.op[1]));
294
bft_error(__FILE__, __LINE__, 0, "not implemented\n");
298
bft_error(__FILE__, __LINE__, 0, "not implemented\n");
303
switch(p->type->opr.oper) {
306
while(_evaluate(p->type->opr.op[0])) _evaluate(p->type->opr.op[1]);
310
if (_evaluate(p->type->opr.op[0]))
311
_evaluate(p->type->opr.op[1]);
312
else if (p->type->opr.nops > 2)
313
_evaluate(p->type->opr.op[2]);
317
bft_printf("PRINT %f\n", _evaluate(p->type->opr.op[0]));
321
_evaluate(p->type->opr.op[0]);
322
return _evaluate(p->type->opr.op[1]);
325
t2 = _evaluate(p->type->opr.op[1]);
326
mei_hash_table_insert(p->ht,
327
p->type->opr.op[0]->type->id.i,
337
return _evaluate(p->type->opr.op[0]);
340
return -_evaluate(p->type->opr.op[0]);
343
return _evaluate(p->type->opr.op[0]) + _evaluate(p->type->opr.op[1]);
346
return _evaluate(p->type->opr.op[0]) - _evaluate(p->type->opr.op[1]);
349
return _evaluate(p->type->opr.op[0]) * _evaluate(p->type->opr.op[1]);
352
t1 = _evaluate(p->type->opr.op[0]);
353
t2 = _evaluate(p->type->opr.op[1]);
357
bft_error(__FILE__, __LINE__, 0, "Error: floating point exception\n");
360
return pow(_evaluate(p->type->opr.op[0]), _evaluate(p->type->opr.op[1]));
363
return _evaluate(p->type->opr.op[0]) < _evaluate(p->type->opr.op[1]);
366
return _evaluate(p->type->opr.op[0]) > _evaluate(p->type->opr.op[1]);
369
return ! _evaluate(p->type->opr.op[0]);
372
return _evaluate(p->type->opr.op[0]) >= _evaluate(p->type->opr.op[1]);
375
return _evaluate(p->type->opr.op[0]) <= _evaluate(p->type->opr.op[1]);
378
return _evaluate(p->type->opr.op[0]) != _evaluate(p->type->opr.op[1]);
381
return _evaluate(p->type->opr.op[0]) == _evaluate(p->type->opr.op[1]);
384
return _evaluate(p->type->opr.op[0]) && _evaluate(p->type->opr.op[1]);
387
return _evaluate(p->type->opr.op[0]) || _evaluate(p->type->opr.op[1]);
395
* \brief Store error message.
397
* \param [in] ev interpreter
401
_manage_error(mei_tree_t *ev)
408
ev->errors = mei_glob_ierr_list;
410
BFT_MALLOC(ev->labels, mei_glob_ierr_list, char*);
411
BFT_MALLOC(ev->lines, mei_glob_ierr_list, int);
412
BFT_MALLOC(ev->columns, mei_glob_ierr_list, int);
414
for (i=0; i<ev->errors; i++) {
415
ev->lines[i] = mei_glob_line_list[i];
416
ev->columns[i] = mei_glob_column_list[i];
418
l = strlen(mei_glob_label_list[i]) + 1;
419
BFT_MALLOC(ev->labels[i], l, char);
420
strncpy(ev->labels[i], mei_glob_label_list[i], l);
425
* \brief Check if the symbol \em str exists in the expression stored
426
* in \em ev. Return 0 if the symbol exists in the symbol table, 1 if not.
428
* \param [in] ev interpreter in which we want to know if \em str exists
429
* \param [in] str symbol to find
430
* \return 0 if the symbol exists in the symbol table, 1 if not
434
_find_symbol(mei_tree_t *ev,
443
if (!mei_hash_table_lookup(ev->symbol, str)) {
445
/* the symbol is not found: this information is stored */
453
BFT_MALLOC(ev->labels, ev->errors, char*);
455
BFT_REALLOC(ev->labels, ev->errors, char*);
458
BFT_MALLOC(ev->labels[i], l, char);
459
strncpy(ev->labels[i], str, l);
465
/*============================================================================
466
* Public function definitions
467
*============================================================================*/
470
* \brief Returns a new interpreter. The node member is empty,
471
* the string member contains the mathematical expression and
472
* the symbol table is initialize with the standard symbols.
474
* \param [in] expr string characters of the mathematical expression
475
* \return new empty interpreter
479
mei_tree_new(const char *const expr)
481
mei_tree_t *ev = NULL;
484
assert(expr != NULL);
486
BFT_MALLOC(ev, 1, mei_tree_t);
488
BFT_MALLOC(ev->symbol, 1, hash_table_t);
490
length = strlen(expr)+1;
491
BFT_MALLOC(ev->string, length, char);
493
strncpy(ev->string, expr, length);
495
mei_hash_table_create(ev->symbol, HASHSIZE);
496
ev->symbol->n_inter = 1;
497
mei_hash_table_init(ev->symbol);
499
/* Default initializations */
511
* \brief Returns a new interpreter. The node member is empty,
512
* the string member contains the mathematical expression and
513
* the symbol table is initialize with a existing table, which is shared by
514
* multiple interpreter.
516
* \param [in] expr string characters of the mathematical expression
517
* \param [in] symbol_table shared table of symbols
518
* \return new empty interpreter
522
mei_tree_new_with_shared_symbols(const char *const expr,
523
hash_table_t *const symbol_table)
525
mei_tree_t *ev = NULL;
528
assert(expr != NULL);
529
assert(symbol_table != NULL);
531
BFT_MALLOC(ev, 1, mei_tree_t);
533
length = strlen(expr)+1;
534
BFT_MALLOC(ev->string, length, char);
536
strncpy(ev->string, expr, length);
538
/* copy the adress of the shared table of symbols and
539
incremente the number of interpreters that share this table */
541
ev->symbol = symbol_table;
542
ev->symbol->n_inter++;
544
/* Default initializations */
556
* \brief Returns a new table of symbols.
557
* The table contains standard mathematical symbols.
559
* \return table of symbols
563
mei_table_symbols_new(void)
565
hash_table_t *ht = NULL;
567
BFT_MALLOC(ht, 1, hash_table_t);
569
mei_hash_table_create(ht, HASHSIZE);
571
mei_hash_table_init(ht);
577
* \brief Call the yacc parser.
578
* Return 0 if the parsing is ok, or the number of errors, if errors occurs.
580
* \param [in] ev interpreter
581
* \return number of parsing errors
585
mei_tree_builder(mei_tree_t *ev)
591
/* Initialize the global variables of the parser */
592
/*-----------------------------------------------*/
594
/* Initialize the pointer on the node returned by the parser */
596
mei_glob_root = NULL;
598
/* Begin/end of the expression is set in these global variables */
600
mei_glob_string_begin = ev->string;
601
mei_glob_string_end = ev->string + strlen(ev->string);
603
/* Initialize line and column counters,
604
incrementation is done in scanner.l */
609
/* Initialize error counter
610
incrementation is done in parser.y (yyerror function) */
612
mei_glob_ierr_list = 0;
614
/* Parse the expression string and construct the interpreter */
615
/*-----------------------------------------------------------*/
619
if (mei_glob_ierr_list)
622
/* Parsing error: copy informations for display */
626
/* Free memory. Warning: if there is more than one error,
627
not all pointers are cleaning */
629
mei_free_node(mei_glob_root);
633
/* If the parsing is ok, copy the data in the current interpreter */
635
ev->node = mei_glob_root;
637
/* For all nodes of the interpreter, copy the symbols table pointer */
639
_init_symbol_table(ev->node, ev->symbol);
641
/* Check if all new symbols are defined in the expression string */
643
mei_glob_ierr_list = _check_symbol(ev->node);
645
if (mei_glob_ierr_list)
648
/* Check symbol error: copy informations for display */
650
/* if (mei_glob_ierr_list == 1) */
651
/* bft_printf("Warning: there is %i error.\n", mei_glob_ierr_list); */
652
/* else if (mei_glob_ierr_list > 1) */
653
/* bft_printf("Warning: there are %i errors.\n", mei_glob_ierr_list); */
660
/* Free memory of the parser global variables if necessary */
662
for (i=0; i < mei_glob_ierr_list; i++)
663
BFT_FREE(mei_glob_label_list[i]);
665
BFT_FREE(mei_glob_label_list);
666
BFT_FREE(mei_glob_line_list);
667
BFT_FREE(mei_glob_column_list);
669
return mei_glob_ierr_list;
673
* \brief Inserts a constant (label and value) in the table of symbols
674
* associated to an interpreter.
676
* \param [in] ev interpreter
677
* \param [in] str label of the constant
678
* \param [in] value value associated to the constant
682
mei_tree_insert(mei_tree_t *ev,
689
mei_hash_table_insert(ev->symbol,
700
* \brief Inserts a constant (label and value) in a table of symbols.
702
* \param [in] symbol_table table of symbols
703
* \param [in] str label of the constant
704
* \param [in] value value associated to the constant
708
mei_symbol_table_insert(hash_table_t *symbol_table,
712
assert(symbol_table!= NULL);
715
mei_hash_table_insert(symbol_table,
726
* \brief Check if the symbol \em str exists in the expression stored
728
* Return 0 if the symbol exists in the symbol table, 1 if not.
730
* \param [in] ev interpreter in which we want to know if str exists
731
* \param [in] str symbol to find
732
* \return 0 if the symbol exists in the symbol table, 1 if not
736
mei_tree_find_symbol(mei_tree_t *ev,
744
/* restart error's counter */
746
for (i=0; i < ev->errors; i++)
747
BFT_FREE(ev->labels[i]);
749
BFT_FREE(ev->labels);
751
BFT_FREE(ev->columns);
754
return _find_symbol(ev, str);
758
* \brief Check if the symbol \em str from a list exists in the expression.
759
* Return 0 if all symbols exist, otherwise return the number of errors.
760
* The list of missing symbols is stored in \em ev->labels.
762
* \param [in] ev interpreter
763
* \param [in] size number of symbols to check
764
* \param [in] symbol list of symbols
765
* \return 0 if all symbols exist, otherwise return the number of errors
769
mei_tree_find_symbols(mei_tree_t *ev,
777
/* restart error's counter */
779
for (i=0; i < ev->errors; i++)
780
BFT_FREE(ev->labels[i]);
782
BFT_FREE(ev->labels);
784
BFT_FREE(ev->columns);
787
/* check if each symbol from the list exists */
789
for (i=0; i<size; i++)
790
iok += _find_symbol(ev, symbol[i]);
796
* \brief Returns a value of the \em str symbol (variable or constant)
797
* from table of symbols of \em ev interpreter.
799
* \param [in] ev interpreter
800
* \param [in] str name of the symbol
801
* \return value of a symbol
805
mei_tree_lookup(mei_tree_t *ev,
808
struct item *item = NULL;
813
item = mei_hash_table_lookup(ev->symbol, str);
816
bft_error(__FILE__, __LINE__, 0,
817
"Error in mei_tree_lookup function: "
818
"%s does not exist in the symbol table\n", str);
820
return item->data->value;
824
* \brief Evaluates the expression \em ev :
825
* 1) computes all values for variables inside the expression
826
* 2) returns a value from the intrepreted expression.
828
* \param [in] ev interpreter
829
* \return value from the intrepreted expression
833
mei_evaluate(mei_tree_t *ev)
836
return _evaluate(ev->node);
840
* \brief Free memory and return NULL.
842
* \param [in] ev interpreter
846
mei_tree_destroy(mei_tree_t *ev)
851
if (ev->symbol->n_inter == 1) { /* symbol tables for a single interpreter */
852
mei_hash_table_free(ev->symbol);
853
BFT_FREE(ev->symbol);
856
ev->symbol->n_inter--; /* shared symbol tables */
858
BFT_FREE(ev->string);
859
mei_free_node(ev->node);
861
for (i=0; i < ev->errors; i++)
862
BFT_FREE(ev->labels[i]);
864
BFT_FREE(ev->labels);
866
BFT_FREE(ev->columns);
871
/*----------------------------------------------------------------------------*/
875
#endif /* __cplusplus */